UNPKG

pi-emergence

Version:
247 lines (239 loc) 12.1 kB
"use strict"; var _vectorHandler = _interopRequireDefault(require("../../common/vector-handler.js")); var _agent = _interopRequireDefault(require("../../common/agent.js")); var _neuronConnector = _interopRequireDefault(require("./neuron-connector.js")); var _neuronLayer = _interopRequireDefault(require("./neuron-layer.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _readOnlyError(name) { throw new TypeError("\"" + name + "\" is read-only"); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /** * Logical representation of a neuron in a neural network. * The matrix version (which does all the real work) gets converted to this for visual and intuitive representation. * * @requires: VectorHandler * @requires: Agent * @requires: NeuroApp */ var Neuron = /*#__PURE__*/function () { function Neuron(layer, options) { var _this = this; _classCallCheck(this, Neuron); if (!layer) throw new Error("Neuron must be created with a layer"); if (!layer.app) throw new Error("Neuron must be created with a layer with an app"); if (!options) options = {}; this.layer = layer; this.id = options.id || (Math.random() * 9999999999).toString(36) + "-" + new Date().getTime().toString(); this.app = layer.app; this.selectedColor = "yellow"; this.vectorHandler = options.vectorHandler; this.drawer = options.drawer || Neuron.defaultDrawer; this.speed = 1.0; this.squashFunction = layer.network.squashFunction; this.index = options.index; this.forwardConnectors = []; this.backConnectors = []; this.targetPos = null; this.error = 0.0; // The sum of all the error from the next (to the right) layer this.isBias = options.isBias === true; this.isSelected = options.isSelected === true; this.label = null; this.weightTotal = 0; if (!(this.vectorHandler instanceof _vectorHandler["default"])) { this.vectorHandler = typeof p5 !== "undefined" ? _vectorHandler["default"].createP5Handler() : new _vectorHandler["default"](); } // Neuron border color if (!options.color) options.color = Neuron.defaultColor; this.agent = new _agent["default"](options); this.agent.onPositionUpdate = this.onAgentMove; if (this.isBias) { this.agent.color = options.color || "#88FFFF"; this.agent.backgroundColor = this.agent.color; this.rawValue = 1.0; //typeof options.rawValue === "number" ? options.rawValue : 1.0; this.value = 1.0; //typeof options.value === "number" ? options.value : 1.0; } else { this.rawValue = typeof options.rawValue === "number" ? options.rawValue : 0; this.value = typeof options.value === "number" ? options.value : 0; } this.didDraw = false; this.squash = this.squashFunction.squash; if (typeof this.squash !== "function") { console.warn("this.squashFunction type: " + _typeof(this.squashFunction).toString()); console.warn("this.squash: " + _typeof(this.squash)); throw new Error("Invalid activation function: " + this.squash); } this.movePosition = typeof options.movePosition === "function" ? options.movePosition : function () { return Neuron.moveNeuronPosition(_this); }; this.deSquash = this.squashFunction.getDerivative; this.deSquashPartial = this.squashFunction.getPartialDerivative; if (typeof this.index !== "number" || this.index < 0) this.index = layer.neurons.length; } _createClass(Neuron, [{ key: "setTargetPos", value: function setTargetPos(x, y) { this.targetPos = createVector(x, y); } /** * Connects this neuron to the next and prev layers * @param {NeuronLayer|null} nextLayer - Next layer to connect to * @param {NeuronLayer|null} prevtLayer - Previous layer to connect from * @returns {Neuron} - Return this to allow for chaining */ }, { key: "connect", value: function connect(nextLayer, prevLayer) { var _this2 = this; var initialWeightValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; var connectors = []; if (!!nextLayer) { for (var i = 0; i < nextLayer.neurons.length; i++) { var n = nextLayer.neurons[i]; if (n.isBias !== true) { var options = { weight: initialWeightValue }; var c = new _neuronConnector["default"](this, n, options); connectors.push(c); } } this.forwardConnectors = connectors; } if (!!prevLayer) { var backConnectors = []; for (var _i = 0; _i < prevLayer.neurons.length; _i++) { var _n = prevLayer.neurons[_i]; var _connectors = _n.forwardConnectors.filter(function (c) { return c.dest === _this2; }); backConnectors.push.apply(backConnectors, _toConsumableArray(_connectors)); } this.backConnectors = backConnectors; } return this; } }, { key: "randomizeWeights", value: function randomizeWeights() { var miniMaxValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var connectorCount = this.forwardConnectors.length; miniMaxValue = typeof miniMaxValue !== "number" || miniMaxValue === 0 ? Neuron.maxWeightValue : miniMaxValue; for (var i = 0; i < connectorCount; i++) this.forwardConnectors[i].weight = Neuron.randomWeight(miniMaxValue); } }, { key: "activate", value: function activate() { if (this.backConnectors.length === 0) return this.value; var wt = 0; var rawValues = this.backConnectors.map(function (c) { wt += c.weight; return c.calculate(); }); this.weightTotal = wt; this.rawValue = rawValues.reduce(function (a, b) { return a + b; }, 0); this.value = this.squash(this.rawValue); return this.value; } }, { key: "reset", value: function reset() { var deltas = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; return this; } /** Everything below here is for drawing, event handling, and ui purposes */ }, { key: "select", value: function select() { this.isSelected = !this.isSelected; console.log("Clicked: Layer Index " + this.layer.index + ", Neuron Index:" + this.index + ", Selected" + this.isSelected); if (this.isSelected) { // Do something. } return this.isSelected ? this : null; } }, { key: "isAt", value: function isAt(x, y) { var p = this.agent.position; return dist(x, y, p.x, p.y) < this.agent.size; } /** Fires any time the agent updates position */ }, { key: "onAgentMove", value: function onAgentMove() { // } /** * Optionally updates the position of the neuron, if that's your jam. * Set this.movePosition in your constructor to override it. */ }, { key: "updatePosition", value: function updatePosition() { this.movePosition(); } /** * Draws the neuron * @param {object} parentPos - Index of the drawn neuron - For drawing purposes only */ }, { key: "draw", value: function draw(parentPos) { var pos = !!parentPos ? this.vectorHandler.add(this.agent.position, parentPos) : this.agent.position; this.drawer.draw(pos, this); } }], [{ key: "randomWeight", value: function randomWeight() { var miniMaxValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; miniMaxValue = typeof miniMaxValue !== "number" || miniMaxValue === 0 ? Neuron.maxWeightValue : miniMaxValue; var low = -Math.abs(miniMaxValue); var high = Math.abs(miniMaxValue); return Math.random() * (high - low) + low; } }]); return Neuron; }(); _defineProperty(Neuron, "maxWeightValue", 24); _defineProperty(Neuron, "defaultBackgroundColor", "black"); _defineProperty(Neuron, "defaultDrawer", { draw: function draw(position, sender) { throw new Error("Neuron: No drawer specified."); } }); _defineProperty(Neuron, "moveNeuronPosition", function (neuron) { if (!neuron.targetPos) return false; var app = neuron.app; if (!app) return false; if (typeof app.lastMouseX !== "number" || typeof app.lastMouseY !== "number") return; var pos = neuron.agent.position; var diff = Neuron.vectorHandler.sub(neuron.targetPos, pos); var dist = Neuron.vectorHandler.mag(diff); if (dist <= neuron.speed) { neuron.agent.position = Neuron.vectorHandler.setValues(neuron.agent.position, neuron.targetPos); neuron.targetPos = null; return; } Neuron.vectorHandler.normalize(diff), _readOnlyError("diff"); Neuron.vectorHandler.mult(diff, neuron.speed, true); Neuron.vectorHandler.add(neuron.agent.position, diff, true); }); _defineProperty(Neuron, "defaultColor", "#FFFFFF88"); if (typeof module === 'undefined') { console.log("Can't export. Running Neuron in-browser"); } else { module.exports = Neuron; }