pi-emergence
Version:
Various emergent phenomena
241 lines (231 loc) • 10.9 kB
JavaScript
"use strict";
var _vectorHandler = _interopRequireDefault(require("../../common/vector-handler.js"));
var _neuron2 = _interopRequireDefault(require("../components/neuron.js"));
var _feedForward = _interopRequireDefault(require("../networks/feed-forward.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
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); }
/**
* A visual effect to make it seem like there is some sort of brain activity going on...
* Concretely - It's a little particle thingy that moves along the weights, etc
*/
var NeuronRunner = /*#__PURE__*/function () {
function NeuronRunner(network) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, NeuronRunner);
if (!(network instanceof _feedForward["default"])) throw new Error("NeuronRunner must be created with a feed-forward network type");
this.id = options.id || (Math.random() * 99999999).toString(16);
this.vectorHandler = typeof p5 !== "undefined" ? _vectorHandler["default"].createP5Handler() : new _vectorHandler["default"]();
this.network = network;
this.neuron = options.neuron instanceof _neuron2["default"] ? options.neuron : null;
this.drawer = options.drawer || NeuronRunner.defaultDrawer;
this.repeat = typeof options.repeat !== "number" ? options.repeat === true ? -1 : 0 : options.repeat;
// Visual properties
this.color = options.color || null;
this.borderColor = options.borderColor || null;
this.size = {
width: options.width || 0,
height: options.height || 0
};
this.speed = typeof options.speed === "number" && options.speed >= 0 ? options.speed : 5;
// Cursors
this.position = null;
this.target = null;
this.wayPoints = Array.isArray(options.wayPoints) ? options.wayPoints : [];
this.reverseWayPoints = [];
this.twoWay = options.twoWay === true;
if (this.wayPoints.length > 0) {
this.target = this.wayPoints.shift();
}
if (this.twoWay) {
this.reverseWayPoints.push(this.neuron);
if (this.target) this.reverseWayPoints.push(this.target);
}
// Clean up the properties
if (typeof this.size.width !== "number" || this.size.width <= 0) this.size.width = 4;
if (typeof this.size.height !== "number" || this.size.height <= 0) this.size.height = 4;
if (!this.color && !this.borderColor) this.borderColor = "#FFFFFF77";
// Navigation Functions ---
/** Default callback for any time the runner changes linear direction */
this.onNavigate = function (targetNeuron) {
var targetPos = targetNeuron.agent.position;
if (!targetPos) throw new Error("Invalid targetNeuron during onNavigate(targetNeuron)");
if (_this.wayPoints.length > 0) {
//return this.setNextTarget();
} else {
// End
_this.onComplete();
_this.destroy();
}
return 1;
};
this.onReverse = function () {
console.log("onReverse()");
};
this.onComplete = function () {
console.log("onComplete()");
};
// state management
this.printed = false;
this.isReversed = false;
this.didReverse = false;
}
_createClass(NeuronRunner, [{
key: "setNextTarget",
value: function setNextTarget() {
if (this.wayPoints.length === 0) {
return 0;
}
this.target = this.wayPoints.shift();
if (!this.twoWay) return true;
if (!this.isReversed) this.reverseWayPoints.push(this.target);else if (this.didReverse) {
this.didReverse = false;
this.onReverse();
}
if (this.wayPoints.length === 0) {
// cleared.
if (this.twoWay) {
if (this.isReversed) {
this.isReversed = false;
this.reverseWayPoints = [];
return false;
}
this.isReversed = true;
this.didReverse = true;
this.wayPoints = this.reverseWayPoints;
this.wayPoints.reverse();
this.reverseWayPoints = [];
return 1;
}
return 0;
}
return 1;
}
}, {
key: "destroy",
value: function destroy() {
return this.network.removeRunner(this);
}
}, {
key: "onArrival",
value: function onArrival(neuron) {
var arrival = this.onNavigate(neuron) || 0;
//
return arrival;
}
}, {
key: "run",
value: function run() {
var _neuron, _neuron$layer, _neuron$agent;
var neuron = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!neuron) neuron = this.neuron;
if (((_neuron = neuron) === null || _neuron === void 0 ? void 0 : (_neuron$layer = _neuron.layer) === null || _neuron$layer === void 0 ? void 0 : _neuron$layer.network) !== this.network) throw new Error("NeuronRunner.run called with invalid neuron. Must be part of the network " + this.network.name);
if (!((_neuron$agent = neuron.agent) !== null && _neuron$agent !== void 0 && _neuron$agent.position)) throw new Error("Neuron does not have a valid agent position. Be sure to add neuron.agent");
this.neuron = neuron;
this.position = neuron.agent.position.copy();
if (!!options.target) {
if (!!this.target) this.wayPoints.push(this.target);else this.target = options.target;
}
if (typeof options === "function") {
this.onNavigate = options;
options = {};
} else if (typeof options.onNavigate === "function") {
this.onNavigate = options.onNavigate;
}
this.repeat = typeof options.repeat !== "number" ? options.repeat === true ? -1 : this.repeat : options.repeat;
this.speed = typeof options.speed === "number" && options.speed >= 0 ? options.speed : this.speed;
}
}, {
key: "updatePosition",
value: function updatePosition() {
if (!this.target || !this.position) {
console.warn("NeuronRunner.updatePosition() called : No target (" + this.target + ") or position (" + this.position + ")");
return;
}
var tp = this.target.agent.position;
var diff = this.vectorHandler.sub(tp, this.position);
var dir = diff.normalize();
var dx = dir.x * this.speed;
var dy = dir.y * this.speed;
this.position.add(createVector(dx, dy));
diff = this.vectorHandler.sub(tp, this.position); // See if we overshot it (or arrived)
if (Math.abs(diff.x) < this.speed && Math.abs(diff.y) < this.speed) {
this.vectorHandler.setValues(this.position, tp.x, tp.y);
this.onArrival(this.target);
if (this.wayPoints.length > 0) this.setNextTarget();
}
}
/** Uses p5 - Be sure this is ultimately invoked from a sketch */
}, {
key: "draw",
value: function draw() {
this.drawer.draw(this.position, this);
}
/** Static runner waypoint maps */
}], [{
key: "createStrongestConnectorMap",
value: function createStrongestConnectorMap(neuron) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var waypoints = [neuron];
var current = neuron;
var network = neuron.layer.network;
if (!network) throw new Error("NeuronRunner.createStrongestConnectorMap called with invalid neuron");
var _loop = function _loop() {
var index = 0;
var w = -10000;
current.forwardConnectors.map(function (c, idx) {
var weight = Math.abs(c.weight);
if (weight > w) {
w = weight;
index = idx;
}
});
var next = current.forwardConnectors[index].dest;
waypoints.push(next);
current = next;
};
while (current.forwardConnectors.length > 0) {
_loop();
}
return waypoints;
}
}, {
key: "createRandomConnectorMap",
value: function createRandomConnectorMap(neuron) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var waypoints = [neuron];
var current = neuron;
var network = neuron.layer.network;
if (!network) throw new Error("NeuronRunner.createStrongestConnectorMap called with invalid neuron");
while (current.forwardConnectors.length > 0) {
var index = Math.floor(Math.random() * current.forwardConnectors.length);
var next = current.forwardConnectors[index].dest;
waypoints.push(next);
current = next;
}
return waypoints;
}
}]);
return NeuronRunner;
}();
_defineProperty(NeuronRunner, "_nonce", 0);
_defineProperty(NeuronRunner, "defaultDrawer", {
draw: function draw(position, sender) {
if (NeuronRunner._nonce === 0) {
console.error("NeuronRunner: No drawer specified. Neuron Runners will not be drawn.");
NeuronRunner._nonce++;
}
}
});
if (typeof module === 'undefined') {
console.log("Can't export. Running NeuronLayer in-browser");
} else {
module.exports = NeuronRunner;
}