+25
-16
| { | ||
| "name": "neatjs", | ||
| "version": "0.3.0-1", | ||
| "description": "NeuroEvolution of Augmenting Topologies (NEAT) implemented in Javascript (with tests done in Mocha for verification). Can be used as a node module or in a browser", | ||
| "repo": "OptimusLime/neatjs", | ||
| "description": "NeuroEvolution of Augmenting Topologies (NEAT) implemented in Javascript (with tests done in Mocha for verification). Can be used as a node module or in a browser", | ||
| "version": "0.2.6", | ||
| "keywords": ["Neural Network", "NN", "Artificial Neural Networks", "ANN", "CPPN", "NEAT", "HyperNEAT"], | ||
| "keywords": [ | ||
| "Neural Network", | ||
| "NN", | ||
| "Artificial Neural Networks", | ||
| "ANN", | ||
| "CPPN", | ||
| "NEAT", | ||
| "HyperNEAT" | ||
| ], | ||
| "dependencies": { | ||
| "OptimusLime/cppnjs" : "*" | ||
| "optimuslime/cppnjs": "*", | ||
| "optimuslime/win-utils": "*" | ||
| }, | ||
@@ -15,14 +24,14 @@ "development": {}, | ||
| "neat.js", | ||
| "evolution/iec.js", | ||
| "evolution/multiobjective.js", | ||
| "evolution/novelty.js", | ||
| "genome/neatConnection.js", | ||
| "genome/neatNode.js", | ||
| "genome/neatGenome.js", | ||
| "neatHelp/neatDecoder.js", | ||
| "neatHelp/neatHelp.js", | ||
| "neatHelp/neatParameters.js", | ||
| "types/nodeType.js", | ||
| "utility/genomeSharpToJS.js" | ||
| "evolution/iec.js", | ||
| "evolution/multiobjective.js", | ||
| "evolution/novelty.js", | ||
| "genome/neatConnection.js", | ||
| "genome/neatNode.js", | ||
| "genome/neatGenome.js", | ||
| "neatHelp/neatDecoder.js", | ||
| "neatHelp/neatHelp.js", | ||
| "neatHelp/neatParameters.js", | ||
| "types/nodeType.js", | ||
| "utility/genomeSharpToJS.js" | ||
| ] | ||
| } | ||
| } |
@@ -27,7 +27,9 @@ | ||
| self.gid = (typeof gid === 'string' ? parseFloat(gid) : gid); | ||
| //gid must be a string | ||
| self.gid = typeof gid === "number" ? "" + gid : gid;//(typeof gid === 'string' ? parseFloat(gid) : gid); | ||
| self.weight = (typeof weight === 'string' ? parseFloat(weight) : weight); | ||
| self.sourceID = (typeof srcTgtObj.sourceID === 'string' ? parseFloat(srcTgtObj.sourceID) : srcTgtObj.sourceID); | ||
| self.targetID = (typeof srcTgtObj.targetID === 'string' ? parseFloat(srcTgtObj.targetID) : srcTgtObj.targetID); | ||
| //node ids are strings now -- so make sure to save as string always | ||
| self.sourceID = (typeof srcTgtObj.sourceID === 'number' ? "" + (srcTgtObj.sourceID) : srcTgtObj.sourceID); | ||
| self.targetID = (typeof srcTgtObj.targetID === 'number' ? "" + (srcTgtObj.targetID) : srcTgtObj.targetID); | ||
@@ -34,0 +36,0 @@ //learning rates and modulatory information contained here, not generally used or tested |
@@ -25,3 +25,4 @@ /** | ||
| self.gid = (typeof gid === 'string' ? parseFloat(gid) : gid); | ||
| //gids are strings not numbers -- make it so | ||
| self.gid = typeof gid === "number" ? "" + gid : gid; | ||
| //we only story the string of the activation funciton | ||
@@ -28,0 +29,0 @@ //let cppns deal with actual act functions |
| /** | ||
| * Module dependencies. | ||
| */ | ||
| //none | ||
| var uuid = require('win-utils').cuid; | ||
| /** | ||
@@ -52,3 +51,3 @@ * Expose `neatHelp`. | ||
| { | ||
| var prevInnovationId= -1; | ||
| var prevInnovationId= ""; | ||
@@ -73,3 +72,3 @@ var self = this; | ||
| { | ||
| if(correlationItem.connection1.gid<=prevInnovationId) | ||
| if(uuid.isLessThan(correlationItem.connection1.gid, prevInnovationId) || correlationItem.connection1.gid == prevInnovationId) | ||
| return false; | ||
@@ -81,3 +80,3 @@ | ||
| { | ||
| if(correlationItem.connection2.gid<=prevInnovationId) | ||
| if(uuid.isLessThan(correlationItem.connection2.gid, prevInnovationId) || correlationItem.connection2.gid == prevInnovationId) | ||
| return false; | ||
@@ -100,3 +99,3 @@ | ||
| // Innovation ID's should be in order and not duplicated. | ||
| if(correlationItem.connection1.gid <=prevInnovationId) | ||
| if(uuid.isLessThan(correlationItem.connection1.gid, prevInnovationId) || correlationItem.connection1.gid == prevInnovationId) | ||
| return false; | ||
@@ -103,0 +102,0 @@ |
+34
-23
| { | ||
| "name": "neatjs", | ||
| "description": "NeuroEvolution of Augmenting Topologies (NEAT) implemented in Javascript (with tests done in Mocha for verification). Can be used as a node module or in a browser", | ||
| "keywords": ["Neural Network", "NN", "Artificial Neural Networks", "ANN", "CPPN", "NEAT", "HyperNEAT"], | ||
| "author" : { "name": "Paul Szerlip", | ||
| "email": "Paul.Szerlip@cs.ucf.edu", | ||
| "url": "http://designforcode.com/" }, | ||
| "version": "0.2.6", | ||
| "main":"neat.js", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/OptimusLime/neatjs.git" | ||
| }, | ||
| "bugs" : "https://github.com/OptimusLime/neatjs/issues", | ||
| "license":"MIT", | ||
| "dependencies": { | ||
| "cppnjs" : "0.x.x" | ||
| }, | ||
| "devDependencies": { | ||
| "mocha": "1.1.x", | ||
| "should": "1.1.x", | ||
| "xml2js" : "0.2.x" | ||
| } | ||
| } | ||
| "name": "neatjs", | ||
| "version": "0.3.0-1", | ||
| "description": "NeuroEvolution of Augmenting Topologies (NEAT) implemented in Javascript (with tests done in Mocha for verification). Can be used as a node module or in a browser", | ||
| "keywords": [ | ||
| "Neural Network", | ||
| "NN", | ||
| "Artificial Neural Networks", | ||
| "ANN", | ||
| "CPPN", | ||
| "NEAT", | ||
| "HyperNEAT" | ||
| ], | ||
| "author": { | ||
| "name": "Paul Szerlip", | ||
| "email": "Paul.Szerlip@cs.ucf.edu", | ||
| "url": "http://designforcode.com/" | ||
| }, | ||
| "main": "neat.js", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/OptimusLime/neatjs.git" | ||
| }, | ||
| "bugs": "https://github.com/OptimusLime/neatjs/issues", | ||
| "license": "MIT", | ||
| "dependencies": { | ||
| "cppnjs": "0.x.x", | ||
| "win-utils": "*" | ||
| }, | ||
| "devDependencies": { | ||
| "mocha": "1.1.x", | ||
| "should": "1.1.x", | ||
| "xml2js": "0.2.x" | ||
| } | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| var utils = require('../utility/utilities.js'); | ||
| var cppnActivationFunctions = require('./cppnActivationFunctions.js'); | ||
| var Factory = {}; | ||
| module.exports = Factory; | ||
| Factory.probabilities = []; | ||
| Factory.functions = []; | ||
| Factory.functionTable= {}; | ||
| Factory.createActivationFunction = function(functionID) | ||
| { | ||
| if(!cppnActivationFunctions[functionID]) | ||
| throw new Error("Activation Function doesn't exist!"); | ||
| // For now the function ID is the name of a class that implements IActivationFunction. | ||
| return new cppnActivationFunctions[functionID](); | ||
| }; | ||
| Factory.getActivationFunction = function(functionID) | ||
| { | ||
| var activationFunction = Factory.functionTable[functionID]; | ||
| if(!activationFunction) | ||
| { | ||
| // console.log('Creating: ' + functionID); | ||
| // console.log('ActivationFunctions: '); | ||
| // console.log(cppnActivationFunctions); | ||
| activationFunction = Factory.createActivationFunction(functionID); | ||
| Factory.functionTable[functionID] = activationFunction; | ||
| } | ||
| return activationFunction; | ||
| }; | ||
| Factory.setProbabilities = function(oProbs) | ||
| { | ||
| Factory.probabilities = [];//new double[probs.Count]; | ||
| Factory.functions = [];//new IActivationFunction[probs.Count]; | ||
| var counter = 0; | ||
| for(var key in oProbs) | ||
| { | ||
| Factory.probabilities.push(oProbs[key]); | ||
| Factory.functions.push(Factory.getActivationFunction(key)); | ||
| counter++; | ||
| } | ||
| }; | ||
| Factory.defaultProbabilities = function() | ||
| { | ||
| var oProbs = {'BipolarSigmoid' :.25, 'Sine':.25, 'Gaussian':.25, 'Linear':.25}; | ||
| Factory.setProbabilities(oProbs); | ||
| }; | ||
| Factory.getRandomActivationFunction = function() | ||
| { | ||
| if(Factory.probabilities.length == 0) | ||
| Factory.defaultProbabilities(); | ||
| return Factory.functions[utils.RouletteWheel.singleThrowArray(Factory.probabilities)]; | ||
| }; | ||
| var cppnActivationFunctions = {}; | ||
| module.exports = cppnActivationFunctions; | ||
| //implemented the following: | ||
| //BipolarSigmoid | ||
| //PlainSigmoid | ||
| //Gaussian | ||
| //Linear | ||
| //NullFn | ||
| //Sine | ||
| //StepFunction | ||
| cppnActivationFunctions.ActivationFunction = function(functionObj) | ||
| { | ||
| var self = this; | ||
| self.functionID = functionObj.functionID; | ||
| self.functionString = functionObj.functionString; | ||
| self.functionDescription = functionObj.functionDescription; | ||
| self.calculate = functionObj.functionCalculate; | ||
| self.enclose = functionObj.functionEnclose; | ||
| // console.log('self.calc'); | ||
| // console.log(self.calculate); | ||
| // console.log(self.calculate(0)); | ||
| }; | ||
| //this makes it easy to overwrite an activation function from the outside | ||
| //cppnActivationFunctions.AddActivationFunction("BiplorSigmoid", {NEW IMPLEMENTATION}); | ||
| //this can be useful for customizing certain functions for your domain while maintaining the same names | ||
| cppnActivationFunctions.AddActivationFunction = function(functionName, description) | ||
| { | ||
| cppnActivationFunctions[functionName] = function() | ||
| { | ||
| return new cppnActivationFunctions.ActivationFunction(description); | ||
| } | ||
| }; | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "BipolarSigmoid", | ||
| { | ||
| functionID: 'BipolarSigmoid' , | ||
| functionString: "2.0/(1.0 + exp(-4.9*inputSignal)) - 1.0", | ||
| functionDescription: "bipolar steepend sigmoid", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return (2.0 / (1.0 + Math.exp(-4.9 * inputSignal))) - 1.0; | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "((2.0 / (1.0 + Math.exp(-4.9 *(" + stringToEnclose + ")))) - 1.0)"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "PlainSigmoid", | ||
| { | ||
| functionID: 'PlainSigmoid' , | ||
| functionString: "1.0/(1.0+(exp(-inputSignal)))", | ||
| functionDescription: "Plain sigmoid [xrange -5.0,5.0][yrange, 0.0,1.0]", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return 1.0/(1.0+(Math.exp(-inputSignal))); | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(1.0/(1.0+(Math.exp(-1.0*(" + stringToEnclose + ")))))"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "Gaussian", | ||
| { | ||
| functionID: 'Gaussian', | ||
| functionString: "2*e^(-(input*2.5)^2) - 1", | ||
| functionDescription:"bimodal gaussian", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return 2 * Math.exp(-Math.pow(inputSignal * 2.5, 2)) - 1; | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(2.0 * Math.exp(-Math.pow(" + stringToEnclose + "* 2.5, 2.0)) - 1.0)"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "Linear", | ||
| { | ||
| functionID: 'Linear', | ||
| functionString: "Math.abs(x)", | ||
| functionDescription:"Linear", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return Math.abs(inputSignal); | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(Math.abs(" + stringToEnclose + "))"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "NullFn", | ||
| { | ||
| functionID: 'NullFn', | ||
| functionString: "0", | ||
| functionDescription: "returns 0", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return 0.0; | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(0.0)"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "Sine2", | ||
| { | ||
| functionID: 'Sine2', | ||
| functionString: "Sin(2*inputSignal)", | ||
| functionDescription: "Sine function with doubled period", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return Math.sin(2*inputSignal); | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(Math.sin(2.0*(" + stringToEnclose + ")))"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "Sine", | ||
| { | ||
| functionID: 'Sine', | ||
| functionString: "Sin(inputSignal)", | ||
| functionDescription: "Sine function with normal period", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| return Math.sin(inputSignal); | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(Math.sin(" + stringToEnclose + "))"; | ||
| } | ||
| }); | ||
| cppnActivationFunctions.AddActivationFunction( | ||
| "StepFunction", | ||
| { | ||
| functionID: 'StepFunction', | ||
| functionString: "x<=0 ? 0.0 : 1.0", | ||
| functionDescription: "Step function [xrange -5.0,5.0][yrange, 0.0,1.0]", | ||
| functionCalculate: function(inputSignal) | ||
| { | ||
| if(inputSignal<=0.0) | ||
| return 0.0; | ||
| else | ||
| return 1.0; | ||
| }, | ||
| functionEnclose: function(stringToEnclose) | ||
| { | ||
| return "(((" + stringToEnclose + ') <= 0.0) ? 0.0 : 1.0)'; | ||
| } | ||
| }); |
| { | ||
| "name": "cppnjs", | ||
| "repo": "OptimusLime/cppnjs", | ||
| "description": "Compositional Pattern Producing Networks in javascript (type of artificial neural network)", | ||
| "version": "0.2.4", | ||
| "keywords": [ | ||
| "Neural Networks", | ||
| "ANN", | ||
| "CPPN", | ||
| "NEAT" | ||
| ], | ||
| "dependencies": {}, | ||
| "development": {}, | ||
| "license": "MIT", | ||
| "paths": [ | ||
| "activationFunctions", | ||
| "networks", | ||
| "extras", | ||
| "types", | ||
| "utility" | ||
| ], | ||
| "main": "cppn.js", | ||
| "scripts": [ | ||
| "cppn.js", | ||
| "activationFunctions/cppnActivationFactory.js", | ||
| "activationFunctions/cppnActivationFunctions.js", | ||
| "networks/cppnConnection.js", | ||
| "networks/cppnNode.js", | ||
| "networks/cppn.js", | ||
| "types/nodeType.js", | ||
| "utility/utilities.js", | ||
| "extras/adaptableAdditions.js", | ||
| "extras/pureCPPNAdditions.js", | ||
| "extras/gpuAdditions.js" | ||
| ] | ||
| } |
| var cppnjs = {}; | ||
| //export the cppn library | ||
| module.exports = cppnjs; | ||
| //CPPNs | ||
| cppnjs.cppn = require('./networks/cppn.js'); | ||
| //nodes and connections! | ||
| cppnjs.cppnNode = require('./networks/cppnNode.js'); | ||
| cppnjs.cppnConnection = require('./networks/cppnConnection.js'); | ||
| //all the activations your heart could ever hope for | ||
| cppnjs.cppnActivationFunctions = require('./activationFunctions/cppnActivationFunctions.js'); | ||
| cppnjs.cppnActivationFactory = require('./activationFunctions/cppnActivationFactory.js'); | ||
| //and the utilities to round it out! | ||
| cppnjs.utilities = require('./utility/utilities.js'); | ||
| //exporting the node type | ||
| cppnjs.NodeType = require('./types/nodeType.js'); | ||
| //The purpose of this file is to only extend CPPNs to have additional activation capabilities involving mod connections | ||
| var cppnConnection = require("../networks/cppnConnection.js"); | ||
| //default all the variables that need to be added to handle adaptable activation | ||
| var connectionPrototype = cppnConnection.prototype; | ||
| connectionPrototype.a = 0; | ||
| connectionPrototype.b = 0; | ||
| connectionPrototype.c = 0; | ||
| connectionPrototype.d = 0; | ||
| connectionPrototype.modConnection = 0; | ||
| connectionPrototype.learningRate = 0; | ||
| var CPPN = require("../networks/cppn"); | ||
| //default all the variables that need to be added to handle adaptable activation | ||
| var cppnPrototype = CPPN.prototype; | ||
| cppnPrototype.a = 0; | ||
| cppnPrototype.b = 0; | ||
| cppnPrototype.c = 0; | ||
| cppnPrototype.d = 0; | ||
| cppnPrototype.learningRate = 0; | ||
| cppnPrototype.pre = 0; | ||
| cppnPrototype.post = 0; | ||
| cppnPrototype.adaptable = false; | ||
| cppnPrototype.modulatory = false; | ||
| /// <summary> | ||
| /// This function carries out a single network activation. | ||
| /// It is called by all those methods that require network activations. | ||
| /// </summary> | ||
| /// <param name="maxAllowedSignalDelta"> | ||
| /// The network is not relaxed as long as the absolute value of the change in signals at any given point is greater than this value. | ||
| /// Only positive values are used. If the value is less than or equal to 0, the method will return true without checking for relaxation. | ||
| /// </param> | ||
| /// <returns>True if the network is relaxed, or false if not.</returns> | ||
| cppnPrototype.singleStepInternal = function(maxAllowedSignalDelta) | ||
| { | ||
| var isRelaxed = true; // Assume true. | ||
| var self = this; | ||
| // Calculate each connection's output signal, and add the signals to the target neurons. | ||
| for (var i = 0; i < self.connections.length; i++) { | ||
| if (self.adaptable) | ||
| { | ||
| if (self.connections[i].modConnection <= 0.0) //Normal connection | ||
| { | ||
| self.neuronSignalsBeingProcessed[self.connections[i].targetIdx] += self.neuronSignals[self.connections[i].sourceIdx] * self.connections[i].weight; | ||
| } | ||
| else //modulatory connection | ||
| { | ||
| self.modSignals[self.connections[i].targetIdx] += self.neuronSignals[self.connections[i].sourceIdx] * self.connections[i].weight; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| self.neuronSignalsBeingProcessed[self.connections[i].targetIdx] += self.neuronSignals[self.connections[i].sourceIdx] * self.connections[i].weight; | ||
| } | ||
| } | ||
| // Pass the signals through the single-valued activation functions. | ||
| // Do not change the values of input neurons or neurons that have no activation function because they are part of a module. | ||
| for (var i = self.totalInputNeuronCount; i < self.neuronSignalsBeingProcessed.length; i++) { | ||
| self.neuronSignalsBeingProcessed[i] = self.activationFunctions[i].calculate(self.neuronSignalsBeingProcessed[i]+self.biasList[i]); | ||
| if (self.modulatory) | ||
| { | ||
| //Make sure it's between 0 and 1 | ||
| self.modSignals[i] += 1.0; | ||
| if (self.modSignals[i]!=0.0) | ||
| self.modSignals[i] = utilities.tanh(self.modSignals[i]);//Tanh(modSignals[i]);//(Math.Exp(2 * modSignals[i]) - 1) / (Math.Exp(2 * modSignals[i]) + 1)); | ||
| } | ||
| } | ||
| //TODO Modules not supported in this implementation - don't care | ||
| /*foreach (float f in neuronSignals) | ||
| HyperNEATParameters.distOutput.Write(f.ToString("R") + " "); | ||
| HyperNEATParameters.distOutput.WriteLine(); | ||
| HyperNEATParameters.distOutput.Flush();*/ | ||
| // Move all the neuron signals we changed while processing this network activation into storage. | ||
| if (maxAllowedSignalDelta > 0) { | ||
| for (var i = self.totalInputNeuronCount; i < self.neuronSignalsBeingProcessed.length; i++) { | ||
| // First check whether any location in the network has changed by more than a small amount. | ||
| isRelaxed &= (Math.abs(self.neuronSignals[i] - self.neuronSignalsBeingProcessed[i]) > maxAllowedSignalDelta); | ||
| self.neuronSignals[i] = self.neuronSignalsBeingProcessed[i]; | ||
| self.neuronSignalsBeingProcessed[i] = 0.0; | ||
| } | ||
| } else { | ||
| for (var i = self.totalInputNeuronCount; i < self.neuronSignalsBeingProcessed.length; i++) { | ||
| self.neuronSignals[i] = self.neuronSignalsBeingProcessed[i]; | ||
| self.neuronSignalsBeingProcessed[i] = 0.0; | ||
| } | ||
| } | ||
| // Console.WriteLine(inputNeuronCount); | ||
| if (self.adaptable)//CPPN != null) | ||
| { | ||
| var coordinates = [0,0,0,0]; | ||
| var modValue; | ||
| var weightDelta; | ||
| for (var i = 0; i < self.connections.length; i++) | ||
| { | ||
| if (self.modulatory) | ||
| { | ||
| self.pre = self.neuronSignals[self.connections[i].sourceIdx]; | ||
| self.post = self.neuronSignals[self.connections[i].targetIdx]; | ||
| modValue = self.modSignals[self.connections[i].targetIdx]; | ||
| self.a = self.connections[i].a; | ||
| self.b = self.connections[i].b; | ||
| self.c = self.connections[i].c; | ||
| self.d = self.connections[i].d; | ||
| self.learningRate = self.connections[i].learningRate; | ||
| if (modValue != 0.0 && (self.connections[i].modConnection <= 0.0)) //modulate target neuron if its a normal connection | ||
| { | ||
| self.connections[i].weight += modValue*self.learningRate * (self.a * self.pre * self.post + self.b * self.pre + self.c * self.post + self.d); | ||
| } | ||
| if (Math.abs(self.connections[i].weight) > 5.0) | ||
| { | ||
| self.connections[i].weight = 5.0 * Math.sign(self.connections[i].weight); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| self.pre = self.neuronSignals[self.connections[i].sourceIdx]; | ||
| self.post = self.neuronSignals[self.connections[i].targetIdx]; | ||
| self.a = self.connections[i].a; | ||
| self.b = self.connections[i].b; | ||
| self.c = self.connections[i].c; | ||
| self.learningRate = self.connections[i].learningRate; | ||
| weightDelta = self.learningRate * (self.a * self.pre * self.post + self.b * self.pre + self.c * self.post); | ||
| connections[i].weight += weightDelta; | ||
| // Console.WriteLine(pre + " " + post + " " + learningRate + " " + A + " " + B + " " + C + " " + weightDelta); | ||
| if (Math.abs(self.connections[i].weight) > 5.0) | ||
| { | ||
| self.connections[i].weight = 5.0 * Math.sign(self.connections[i].weight); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| for (var i = self.totalInputNeuronCount; i < self.neuronSignalsBeingProcessed.length; i++) | ||
| { | ||
| self.modSignals[i] = 0.0; | ||
| } | ||
| return isRelaxed; | ||
| }; | ||
| cppnPrototype.singleStep = function(finished) | ||
| { | ||
| var self = this; | ||
| self.singleStepInternal(0.0); // we will ignore the value of this function, so the "allowedDelta" argument doesn't matter. | ||
| if (finished) | ||
| { | ||
| finished(null); | ||
| } | ||
| }; | ||
| cppnPrototype.multipleSteps = function(numberOfSteps) | ||
| { | ||
| var self = this; | ||
| for (var i = 0; i < numberOfSteps; i++) { | ||
| self.singleStep(); | ||
| } | ||
| }; |
| //this takes in cppn functions, and outputs a shader.... | ||
| //radical! | ||
| //needs to be tested more! How large can CPPNs get? inputs/outputs/hiddens? | ||
| //we'll extend a CPPN to produce a GPU shader | ||
| var CPPN = require("../networks/cppn"); | ||
| var CPPNPrototype = CPPN.prototype; | ||
| var cppnToGPU = {}; | ||
| cppnToGPU.ShaderFragments = {}; | ||
| cppnToGPU.ShaderFragments.passThroughVariables = | ||
| [ | ||
| "uniform float texelWidth;", | ||
| "uniform float texelHeight;" | ||
| ].join('\n'); | ||
| //simple, doesn't do anything but pass on uv coords to the frag shaders | ||
| cppnToGPU.ShaderFragments.passThroughVS = | ||
| [ | ||
| cppnToGPU.ShaderFragments.passThroughVariables, | ||
| "varying vec2 passCoord;", | ||
| "void main() {", | ||
| "passCoord = uv;", | ||
| "gl_Position = vec4( position, 1.0 );", | ||
| "}", | ||
| "\n" | ||
| ].join('\n'); | ||
| cppnToGPU.ShaderFragments.passThroughVS3x3 = | ||
| [ | ||
| cppnToGPU.ShaderFragments.passThroughVariables, | ||
| "varying vec2 sampleCoords[9];", | ||
| "void main() {", | ||
| "gl_Position = vec4( position, 1.0 );", | ||
| "vec2 widthStep = vec2(texelWidth, 0.0);", | ||
| "vec2 heightStep = vec2(0.0, texelHeight);", | ||
| "vec2 widthHeightStep = vec2(texelWidth, texelHeight);", | ||
| "vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);", | ||
| "vec2 inputTextureCoordinate = uv;", | ||
| "sampleCoords[0] = inputTextureCoordinate.xy;", | ||
| "sampleCoords[1] = inputTextureCoordinate.xy - widthStep;", | ||
| "sampleCoords[2] = inputTextureCoordinate.xy + widthStep;", | ||
| "sampleCoords[3] = inputTextureCoordinate.xy - heightStep;", | ||
| "sampleCoords[4] = inputTextureCoordinate.xy - widthHeightStep;", | ||
| "sampleCoords[5] = inputTextureCoordinate.xy + widthNegativeHeightStep;", | ||
| "sampleCoords[6] = inputTextureCoordinate.xy + heightStep;", | ||
| "sampleCoords[7] = inputTextureCoordinate.xy - widthNegativeHeightStep;", | ||
| "sampleCoords[8] = inputTextureCoordinate.xy + widthHeightStep;", | ||
| "}", | ||
| "\n" | ||
| ].join('\n'); | ||
| cppnToGPU.ShaderFragments.variables = | ||
| [ | ||
| "varying vec2 passCoord; ", | ||
| "uniform sampler2D inputTexture; " | ||
| ].join('\n'); | ||
| cppnToGPU.ShaderFragments.variables3x3 = | ||
| [ | ||
| "varying vec2 sampleCoords[9];", | ||
| "uniform sampler2D inputTexture; " | ||
| ].join('\n'); | ||
| //this is a generic conversion from cppn to shader | ||
| //Extends the CPPN object to have fullShaderFromCPPN function (and a callback to add any extras) | ||
| //the extras will actually dictate how the final output is created and used | ||
| CPPNPrototype.fullShaderFromCPPN = function(specificAddFunction) | ||
| { | ||
| var cppn = this; | ||
| // console.log('Decoded!'); | ||
| // console.log('Start enclose :)'); | ||
| var functionObject = cppn.createPureCPPNFunctions(); | ||
| // console.log('End enclose!'); | ||
| //functionobject of the form | ||
| // {contained: contained, stringFunctions: stringFunctions, arrayIdentifier: "this.rf", nodeOrder: inOrderAct}; | ||
| var multiInput = cppn.inputNeuronCount >= 27; | ||
| var totalNeurons = cppn.totalNeuronCount; | ||
| var inorderString = ""; | ||
| var lastIx = functionObject.nodeOrder[totalNeurons-1]; | ||
| functionObject.nodeOrder.forEach(function(ix) | ||
| { | ||
| inorderString += ix + (ix !== lastIx ? "," : ""); | ||
| }); | ||
| var defaultVariables = multiInput ? cppnToGPU.ShaderFragments.variables3x3 : cppnToGPU.ShaderFragments.variables; | ||
| //create a float array the size of the neurons | ||
| // var fixedArrayDec = "int order[" + totalNeurons + "](" + inorderString + ");"; | ||
| var arrayDeclaration = "float register[" + totalNeurons + "];"; | ||
| var beforeFunctionIx = "void f"; | ||
| var functionWrap = "(){"; | ||
| var postFunctionWrap = "}"; | ||
| var repString = functionObject.arrayIdentifier; | ||
| var fns = functionObject.stringFunctions; | ||
| var wrappedFunctions = []; | ||
| for(var key in fns) | ||
| { | ||
| if(key < cppn.totalInputNeuronCount) | ||
| continue; | ||
| //do this as 3 separate lines | ||
| var wrap = beforeFunctionIx + key + functionWrap; | ||
| wrappedFunctions.push(wrap); | ||
| var setRegister = "register[" + key + "] = "; | ||
| var repFn = fns[key].replace(new RegExp(repString, 'g'), "register"); | ||
| //remove all Math. references -- e.g. Math.sin == sin in gpu code | ||
| repFn = repFn.replace(new RegExp("Math.", 'g'), ""); | ||
| //we don't want a return function, fs are void | ||
| repFn = repFn.replace(new RegExp("return ", 'g'), ""); | ||
| //anytime you see a +-, this actually means - | ||
| //same goes for -- this is a + | ||
| repFn = repFn.replace(new RegExp("\\+\\-", 'g'), "-"); | ||
| repFn = repFn.replace(new RegExp("\\-\\-", 'g'), "+"); | ||
| wrappedFunctions.push(setRegister + repFn); | ||
| wrappedFunctions.push(postFunctionWrap); | ||
| } | ||
| var activation = []; | ||
| var actBefore, additionalParameters; | ||
| if(cppn.outputNeuronCount == 1) | ||
| { | ||
| actBefore = "float"; | ||
| additionalParameters = ""; | ||
| } | ||
| else | ||
| { | ||
| // actBefore = "float[" + ng.outputNodeCount + "]"; | ||
| actBefore = "void"; | ||
| additionalParameters = ", out float[" + cppn.outputNeuronCount + "] outputs"; | ||
| } | ||
| actBefore += " activate(float[" +cppn.inputNeuronCount + "] fnInputs" + additionalParameters+ "){"; | ||
| activation.push(actBefore); | ||
| var bCount = cppn.biasNeuronCount; | ||
| for(var i=0; i < bCount; i++) | ||
| { | ||
| activation.push('register[' + i + '] = 1.0;'); | ||
| } | ||
| for(var i=0; i < cppn.inputNeuronCount; i++) | ||
| { | ||
| activation.push('register[' + (i + bCount) + '] = fnInputs[' + i + '];'); | ||
| } | ||
| functionObject.nodeOrder.forEach(function(ix) | ||
| { | ||
| if(ix >= cppn.totalInputNeuronCount) | ||
| activation.push("f"+ix +"();"); | ||
| }); | ||
| var outputs; | ||
| //if you're just one output, return a simple float | ||
| //otherwise, you need to return an array | ||
| if(cppn.outputNeuronCount == 1) | ||
| { | ||
| outputs = "return register[" + cppn.totalInputNeuronCount + "];"; | ||
| } | ||
| else | ||
| { | ||
| var multiOut = []; | ||
| // multiOut.push("float o[" + ng.outputNodeCount + "];"); | ||
| for(var i=0; i < cppn.outputNeuronCount; i++) | ||
| multiOut.push("outputs[" + i + "] = register[" + (i + cppn.totalInputNeuronCount) + "];"); | ||
| // multiOut.push("return o;"); | ||
| outputs = multiOut.join('\n'); | ||
| } | ||
| activation.push(outputs); | ||
| activation.push("}"); | ||
| var additional = specificAddFunction(cppn); | ||
| return {vertex: multiInput ? | ||
| cppnToGPU.ShaderFragments.passThroughVS3x3 : | ||
| cppnToGPU.ShaderFragments.passThroughVS, | ||
| fragment: [defaultVariables,arrayDeclaration].concat(wrappedFunctions).concat(activation).concat(additional).join('\n')}; | ||
| }; | ||
| //The purpose of this file is to only extend CPPNs to have additional activation capabilities involving turning | ||
| //cppns into a string! | ||
| var CPPN = require("../networks/cppn"); | ||
| //for convenience, you can require pureCPPNAdditions | ||
| module.exports = CPPN; | ||
| var CPPNPrototype = CPPN.prototype; | ||
| CPPNPrototype.createPureCPPNFunctions = function() | ||
| { | ||
| var self = this; | ||
| //create our enclosed object for each node! (this way we actually have subnetworks functions setup too | ||
| self.nEnclosed = new Array(self.neuronSignals.length); | ||
| self.bAlreadyEnclosed = new Array(self.neuronSignals.length); | ||
| self.inEnclosure = new Array(self.neuronSignals.length); | ||
| // Initialize boolean arrays and set the last activation signal, but only if it isn't an input (these have already been set when the input is activated) | ||
| for (var i = 0; i < self.nEnclosed.length; i++) | ||
| { | ||
| // Set as activated if i is an input node, otherwise ensure it is unactivated (false) | ||
| self.bAlreadyEnclosed[i] = (i < self.totalInputNeuronCount) ? true : false; | ||
| self.nEnclosed[i] = (i < self.totalInputNeuronCount ? "x" + i : ""); | ||
| self.inEnclosure[i] = false; | ||
| } | ||
| // Get each output node activation recursively | ||
| // NOTE: This is an assumption that genomes have started minimally, and the output nodes lie sequentially after the input nodes | ||
| for (var i = 0; i < self.outputNeuronCount; i++){ | ||
| // for (var m = 0; m < self.nEnclosed.length; m++) | ||
| // { | ||
| // // Set as activated if i is an input node, otherwise ensure it is unactivated (false) | ||
| // self.bAlreadyEnclosed[m] = (m < self.totalInputNeuronCount) ? true : false; | ||
| // self.inEnclosure[m] = false; | ||
| // } | ||
| self.nrEncloseNode(self.totalInputNeuronCount + i); | ||
| } | ||
| // console.log(self.nEnclosed); | ||
| //now grab our ordered objects | ||
| var orderedObjects = self.recursiveCountThings(); | ||
| // console.log(orderedObjects); | ||
| //now let's build our functions | ||
| var nodeFunctions = {}; | ||
| var stringFunctions = {}; | ||
| var emptyNodes = {}; | ||
| for(var i= self.totalInputNeuronCount; i < self.totalNeuronCount; i++) | ||
| { | ||
| //skip functions that aren't defined | ||
| if(!self.bAlreadyEnclosed[i]){ | ||
| emptyNodes[i] = true; | ||
| continue; | ||
| } | ||
| var fnString = "return " + self.nEnclosed[i] + ';'; | ||
| nodeFunctions[i] = new Function([], fnString); | ||
| stringFunctions[i] = fnString; | ||
| } | ||
| var inOrderAct = []; | ||
| //go through and grab the indices -- no need for rank and things | ||
| orderedObjects.forEach(function(oNode) | ||
| { | ||
| if(!emptyNodes[oNode.node]) | ||
| inOrderAct.push(oNode.node); | ||
| }); | ||
| var containedFunction = function(nodesInOrder, functionsForNodes, biasCount, outputCount) | ||
| { | ||
| return function(inputs) | ||
| { | ||
| var bias = 1.0; | ||
| var context = {}; | ||
| context.rf = new Array(nodesInOrder.length); | ||
| var totalIn = inputs.length + biasCount; | ||
| for(var i=0; i < biasCount; i++) | ||
| context.rf[i] = bias; | ||
| for(var i=0; i < inputs.length; i++) | ||
| context.rf[i+biasCount] = inputs[i]; | ||
| for(var i=0; i < nodesInOrder.length; i++) | ||
| { | ||
| var fIx = nodesInOrder[i]; | ||
| // console.log('Ix to hit: ' fIx + ); | ||
| context.rf[fIx] = (fIx < totalIn ? context.rf[fIx] : functionsForNodes[fIx].call(context)); | ||
| } | ||
| return context.rf.slice(totalIn, totalIn + outputCount); | ||
| } | ||
| }; | ||
| //this will return a function that can be run by calling var outputs = functionName(inputs); | ||
| var contained = containedFunction(inOrderAct, nodeFunctions, self.biasNeuronCount, self.outputNeuronCount); | ||
| return {contained: contained, stringFunctions: stringFunctions, arrayIdentifier: "this.rf", nodeOrder: inOrderAct}; | ||
| // console.log(self.nEnclosed[self.totalInputNeuronCount + 0].length); | ||
| // console.log('Enclosed nodes: '); | ||
| // console.log(self.nEnclosed); | ||
| // console.log('Ordered: '); | ||
| // console.log(orderedActivation); | ||
| }; | ||
| CPPNPrototype.nrEncloseNode = function(currentNode) | ||
| { | ||
| var self = this; | ||
| // If we've reached an input node we return since the signal is already set | ||
| // console.log('Checking: ' + currentNode); | ||
| // console.log('Total: '); | ||
| // console.log(self.totalInputNeuronCount); | ||
| if (currentNode < self.totalInputNeuronCount) | ||
| { | ||
| self.inEnclosure[currentNode] = false; | ||
| self[currentNode] = 'this.rf[' + currentNode + ']'; | ||
| return; | ||
| } | ||
| if (self.bAlreadyEnclosed[currentNode]) | ||
| { | ||
| self.inEnclosure[currentNode] = false; | ||
| return; | ||
| } | ||
| // Mark that the node is currently being calculated | ||
| self.inEnclosure[currentNode] = true; | ||
| // Adjacency list in reverse holds incoming connections, go through each one and activate it | ||
| for (var i = 0; i < self.reverseAdjacentList[currentNode].length; i++) | ||
| { | ||
| var crntAdjNode = self.reverseAdjacentList[currentNode][i]; | ||
| //{ Region recurrant connection handling - not applicable in our implementation | ||
| // If this node is currently being activated then we have reached a cycle, or recurrant connection. Use the previous activation in this case | ||
| if (self.inEnclosure[crntAdjNode]) | ||
| { | ||
| //easy fix, this isn't meant for recurrent networks -- just throw an error! | ||
| throw new Error("Method not built for recurrent networks!"); | ||
| } | ||
| // Otherwise proceed as normal | ||
| else | ||
| { | ||
| // Recurse if this neuron has not been activated yet | ||
| if (!self.bAlreadyEnclosed[crntAdjNode]) | ||
| self.nrEncloseNode(crntAdjNode); | ||
| // console.log('Next: '); | ||
| // console.log(crntAdjNode); | ||
| // console.log(self.nEnclosed[crntAdjNode]); | ||
| var add = (self.nEnclosed[currentNode] == "" ? "(" : "+"); | ||
| //get our weight from adjacency matrix | ||
| var weight = self.adjacentMatrix[crntAdjNode][currentNode]; | ||
| //we have a whole number weight! | ||
| if(Math.round(weight) === weight) | ||
| weight = '' + weight + '.0'; | ||
| else | ||
| weight = '' + weight; | ||
| // Add it to the new activation | ||
| self.nEnclosed[currentNode] += add + weight + "*" + "this.rf[" + crntAdjNode + "]"; | ||
| } | ||
| //} endregion | ||
| // nodeCount++; | ||
| } | ||
| //if we're empty, we're empty! We don't go no where, derrrr | ||
| if(self.nEnclosed[currentNode] === '') | ||
| self.nEnclosed[currentNode] = '0.0'; | ||
| else | ||
| self.nEnclosed[currentNode] += ')'; | ||
| // Mark this neuron as completed | ||
| self.bAlreadyEnclosed[currentNode] = true; | ||
| // This is no longer being calculated (for cycle detection) | ||
| self.inEnclosure[currentNode] = false; | ||
| // console.log('Enclosed legnth: ' + self.activationFunctions[currentNode].enclose(self.nEnclosed[currentNode]).length); | ||
| self.nEnclosed[currentNode] = self.activationFunctions[currentNode].enclose(self.nEnclosed[currentNode]); | ||
| }; | ||
| CPPNPrototype.recursiveCountThings = function() | ||
| { | ||
| var self= this; | ||
| var orderedActivation = {}; | ||
| var higherLevelRecurse = function(neuron) | ||
| { | ||
| var inNode = new Array(self.totalNeuronCount); | ||
| var nodeCount = new Array(self.totalNeuronCount); | ||
| var interactCount = new Array(self.totalNeuronCount); | ||
| for(var s=0; s < self.totalNeuronCount; s++) { | ||
| inNode[s] = false; | ||
| nodeCount[s] = 0; | ||
| interactCount[s] = 0; | ||
| } | ||
| var recurseNode = function(currentNode) | ||
| { | ||
| // Mark that the node is currently being calculated | ||
| inNode[currentNode] = true; | ||
| var recurse = {}; | ||
| // Adjacency list in reverse holds incoming connections, go through each one and activate it | ||
| for (var i = 0; i < self.reverseAdjacentList[currentNode].length; i++) | ||
| { | ||
| var crntAdjNode = self.reverseAdjacentList[currentNode][i]; | ||
| recurse[i] = (nodeCount[crntAdjNode] < nodeCount[currentNode] + 1); | ||
| nodeCount[crntAdjNode] = Math.max(nodeCount[crntAdjNode], nodeCount[currentNode] + 1); | ||
| } | ||
| //all nodes are marked with correct count, let's continue backwards for each one! | ||
| for (var i = 0; i < self.reverseAdjacentList[currentNode].length; i++) | ||
| { | ||
| var crntAdjNode = self.reverseAdjacentList[currentNode][i]; | ||
| if(recurse[i]) | ||
| // Recurse on it! -- already marked above | ||
| recurseNode(crntAdjNode); | ||
| } | ||
| // nodeCount[currentNode] = nodeCount[currentNode] + 1; | ||
| inNode[currentNode] = false; | ||
| }; | ||
| recurseNode(neuron); | ||
| return nodeCount; | ||
| }; | ||
| var orderedObjects = new Array(self.totalNeuronCount); | ||
| // Get each output node activation recursively | ||
| // NOTE: This is an assumption that genomes have started minimally, and the output nodes lie sequentially after the input nodes | ||
| for (var m = 0; m < self.outputNeuronCount; m++){ | ||
| //we have ordered count for this output! | ||
| var olist = higherLevelRecurse(self.totalInputNeuronCount + m); | ||
| var nodeSpecificOrdering = []; | ||
| for(var n=0; n< olist.length; n++) | ||
| { | ||
| //we take the maximum depending on whether or not it's been seen before | ||
| if(orderedObjects[n]) | ||
| orderedObjects[n] = {node: n, rank: Math.max(orderedObjects[n].rank, olist[n])}; | ||
| else | ||
| orderedObjects[n] = {node: n, rank: olist[n]}; | ||
| nodeSpecificOrdering.push({node: n, rank: olist[n]}); | ||
| } | ||
| nodeSpecificOrdering.sort(function(a,b){return b.rank - a.rank;}); | ||
| orderedActivation[self.totalInputNeuronCount + m] = nodeSpecificOrdering; | ||
| } | ||
| orderedObjects.sort(function(a,b){return b.rank - a.rank;}); | ||
| // console.log(orderedObjects); | ||
| return orderedObjects; | ||
| }; |
| /** | ||
| * Module dependencies. | ||
| */ | ||
| var utilities = require('../utility/utilities.js'); | ||
| /** | ||
| * Expose `CPPN`. | ||
| */ | ||
| module.exports = CPPN; | ||
| /** | ||
| * Initialize a new error view. | ||
| * | ||
| * @param {Number} biasNeuronCount | ||
| * @param {Number} inputNeuronCount | ||
| * @param {Number} outputNeuronCount | ||
| * @param {Number} totalNeuronCount | ||
| * @param {Array} connections | ||
| * @param {Array} biasList | ||
| * @param {Array} activationFunctions | ||
| * @api public | ||
| */ | ||
| function CPPN( | ||
| biasNeuronCount, | ||
| inputNeuronCount, | ||
| outputNeuronCount, | ||
| totalNeuronCount, | ||
| connections, | ||
| biasList, | ||
| activationFunctions | ||
| ) | ||
| { | ||
| var self = this; | ||
| // must be in the same order as neuronSignals. Has null entries for neurons that are inputs or outputs of a module. | ||
| self.activationFunctions = activationFunctions; | ||
| // The modules and connections are in no particular order; only the order of the neuronSignals is used for input and output methods. | ||
| //floatfastconnections | ||
| self.connections = connections; | ||
| /// The number of bias neurons, usually one but sometimes zero. This is also the index of the first input neuron in the neuron signals. | ||
| self.biasNeuronCount = biasNeuronCount; | ||
| /// The number of input neurons. | ||
| self.inputNeuronCount = inputNeuronCount; | ||
| /// The number of input neurons including any bias neurons. This is also the index of the first output neuron in the neuron signals. | ||
| self.totalInputNeuronCount = self.biasNeuronCount + self.inputNeuronCount; | ||
| /// The number of output neurons. | ||
| self.outputNeuronCount = outputNeuronCount; | ||
| //save the total neuron count for us | ||
| self.totalNeuronCount = totalNeuronCount; | ||
| // For the following array, neurons are ordered with bias nodes at the head of the list, | ||
| // then input nodes, then output nodes, and then hidden nodes in the array's tail. | ||
| self.neuronSignals = []; | ||
| self.modSignals = []; | ||
| // This array is a parallel of neuronSignals, and only has values during SingleStepInternal(). | ||
| // It is declared here to avoid having to reallocate it for every network activation. | ||
| self.neuronSignalsBeingProcessed = []; | ||
| //initialize the neuron,mod, and processing signals | ||
| for(var i=0; i < totalNeuronCount; i++){ | ||
| //either you are 1 for bias, or 0 otherwise | ||
| self.neuronSignals.push(i < self.biasNeuronCount ? 1 : 0); | ||
| self.modSignals.push(0); | ||
| self.neuronSignalsBeingProcessed.push(0); | ||
| } | ||
| self.biasList = biasList; | ||
| // For recursive activation, marks whether we have finished this node yet | ||
| self.activated = []; | ||
| // For recursive activation, makes whether a node is currently being calculated. For recurrant connections | ||
| self.inActivation = []; | ||
| // For recursive activation, the previous activation for recurrent connections | ||
| self.lastActivation = []; | ||
| self.adjacentList = []; | ||
| self.reverseAdjacentList = []; | ||
| self.adjacentMatrix = []; | ||
| //initialize the activated, in activation, previous activation | ||
| for(var i=0; i < totalNeuronCount; i++){ | ||
| self.activated.push(false); | ||
| self.inActivation.push(false); | ||
| self.lastActivation.push(0); | ||
| //then we initialize our list of lists! | ||
| self.adjacentList.push([]); | ||
| self.reverseAdjacentList.push([]); | ||
| self.adjacentMatrix.push([]); | ||
| for(var j=0; j < totalNeuronCount; j++) | ||
| { | ||
| self.adjacentMatrix[i].push(0); | ||
| } | ||
| } | ||
| // console.log(self.adjacentList.length); | ||
| //finally | ||
| // Set up adjacency list and matrix | ||
| for (var i = 0; i < self.connections.length; i++) | ||
| { | ||
| var crs = self.connections[i].sourceIdx; | ||
| var crt = self.connections[i].targetIdx; | ||
| // Holds outgoing nodes | ||
| self.adjacentList[crs].push(crt); | ||
| // Holds incoming nodes | ||
| self.reverseAdjacentList[crt].push(crs); | ||
| self.adjacentMatrix[crs][crt] = connections[i].weight; | ||
| } | ||
| } | ||
| /// <summary> | ||
| /// Using RelaxNetwork erodes some of the perofrmance gain of FastConcurrentNetwork because of the slightly | ||
| /// more complex implemementation of the third loop - whe compared to SingleStep(). | ||
| /// </summary> | ||
| /// <param name="maxSteps"></param> | ||
| /// <param name="maxAllowedSignalDelta"></param> | ||
| /// <returns></returns> | ||
| CPPN.prototype.relaxNetwork = function(maxSteps, maxAllowedSignalDelta) | ||
| { | ||
| var self = this; | ||
| var isRelaxed = false; | ||
| for (var j = 0; j < maxSteps && !isRelaxed; j++) { | ||
| isRelaxed = self.singleStepInternal(maxAllowedSignalDelta); | ||
| } | ||
| return isRelaxed; | ||
| }; | ||
| CPPN.prototype.setInputSignal = function(index, signalValue) | ||
| { | ||
| var self = this; | ||
| // For speed we don't bother with bounds checks. | ||
| self.neuronSignals[self.biasNeuronCount + index] = signalValue; | ||
| }; | ||
| CPPN.prototype.setInputSignals = function(signalArray) | ||
| { | ||
| var self = this; | ||
| // For speed we don't bother with bounds checks. | ||
| for (var i = 0; i < signalArray.length; i++) | ||
| self.neuronSignals[self.biasNeuronCount + i] = signalArray[i]; | ||
| }; | ||
| //we can dispense of this by accessing neuron signals directly | ||
| CPPN.prototype.getOutputSignal = function(index) | ||
| { | ||
| // For speed we don't bother with bounds checks. | ||
| return this.neuronSignals[this.totalInputNeuronCount + index]; | ||
| }; | ||
| //we can dispense of this by accessing neuron signals directly | ||
| CPPN.prototype.clearSignals = function() | ||
| { | ||
| var self = this; | ||
| // Clear signals for input, hidden and output nodes. Only the bias node is untouched. | ||
| for (var i = self.biasNeuronCount; i < self.neuronSignals.length; i++) | ||
| self.neuronSignals[i] = 0.0; | ||
| }; | ||
| // cppn.CPPN.prototype.TotalNeuronCount = function(){ return this.neuronSignals.length;}; | ||
| CPPN.prototype.recursiveActivation = function(){ | ||
| var self = this; | ||
| // Initialize boolean arrays and set the last activation signal, but only if it isn't an input (these have already been set when the input is activated) | ||
| for (var i = 0; i < self.neuronSignals.length; i++) | ||
| { | ||
| // Set as activated if i is an input node, otherwise ensure it is unactivated (false) | ||
| self.activated[i] = (i < self.totalInputNeuronCount) ? true : false; | ||
| self.inActivation[i] = false; | ||
| if (i >= self.totalInputNeuronCount) | ||
| self.lastActivation[i] = self.neuronSignals[i]; | ||
| } | ||
| // Get each output node activation recursively | ||
| // NOTE: This is an assumption that genomes have started minimally, and the output nodes lie sequentially after the input nodes | ||
| for (var i = 0; i < self.outputNeuronCount; i++) | ||
| self.recursiveActivateNode(self.totalInputNeuronCount + i); | ||
| }; | ||
| CPPN.prototype.recursiveActivateNode = function(currentNode) | ||
| { | ||
| var self = this; | ||
| // If we've reached an input node we return since the signal is already set | ||
| if (self.activated[currentNode]) | ||
| { | ||
| self.inActivation[currentNode] = false; | ||
| return; | ||
| } | ||
| // Mark that the node is currently being calculated | ||
| self.inActivation[currentNode] = true; | ||
| // Set the presignal to 0 | ||
| self.neuronSignalsBeingProcessed[currentNode] = 0; | ||
| // Adjacency list in reverse holds incoming connections, go through each one and activate it | ||
| for (var i = 0; i < self.reverseAdjacentList[currentNode].length; i++) | ||
| { | ||
| var crntAdjNode = self.reverseAdjacentList[currentNode][i]; | ||
| //{ Region recurrant connection handling - not applicable in our implementation | ||
| // If this node is currently being activated then we have reached a cycle, or recurrant connection. Use the previous activation in this case | ||
| if (self.inActivation[crntAdjNode]) | ||
| { | ||
| //console.log('using last activation!'); | ||
| self.neuronSignalsBeingProcessed[currentNode] += self.lastActivation[crntAdjNode]*self.adjacentMatrix[crntAdjNode][currentNode]; | ||
| // parseFloat( | ||
| // parseFloat(self.lastActivation[crntAdjNode].toFixed(9)) * parseFloat(self.adjacentMatrix[crntAdjNode][currentNode].toFixed(9)).toFixed(9)); | ||
| } | ||
| // Otherwise proceed as normal | ||
| else | ||
| { | ||
| // Recurse if this neuron has not been activated yet | ||
| if (!self.activated[crntAdjNode]) | ||
| self.recursiveActivateNode(crntAdjNode); | ||
| // Add it to the new activation | ||
| self.neuronSignalsBeingProcessed[currentNode] += self.neuronSignals[crntAdjNode] *self.adjacentMatrix[crntAdjNode][currentNode]; | ||
| // parseFloat( | ||
| // parseFloat(self.neuronSignals[crntAdjNode].toFixed(9)) * parseFloat(self.adjacentMatrix[crntAdjNode][currentNode].toFixed(9)).toFixed(9)); | ||
| } | ||
| //} endregion | ||
| } | ||
| // Mark this neuron as completed | ||
| self.activated[currentNode] = true; | ||
| // This is no longer being calculated (for cycle detection) | ||
| self.inActivation[currentNode] = false; | ||
| // console.log('Current node: ' + currentNode); | ||
| // console.log('ActivationFunctions: '); | ||
| // console.log(self.activationFunctions); | ||
| // | ||
| // console.log('neuronSignals: '); | ||
| // console.log(self.neuronSignals); | ||
| // | ||
| // console.log('neuronSignalsBeingProcessed: '); | ||
| // console.log(self.neuronSignalsBeingProcessed); | ||
| // Set this signal after running it through the activation function | ||
| self.neuronSignals[currentNode] = self.activationFunctions[currentNode].calculate(self.neuronSignalsBeingProcessed[currentNode]); | ||
| // parseFloat((self.activationFunctions[currentNode].calculate(parseFloat(self.neuronSignalsBeingProcessed[currentNode].toFixed(9)))).toFixed(9)); | ||
| }; | ||
| CPPN.prototype.isRecursive = function() | ||
| { | ||
| var self = this; | ||
| //if we're a hidden/output node (nodeid >= totalInputcount), and we connect to an input node (nodeid <= self.totalInputcount) -- it's recurrent! | ||
| //if we are a self connection, duh we are recurrent | ||
| for(var c=0; c< self.connections.length; c++) | ||
| if((self.connections[c].sourceIdx >= self.totalInputNeuronCount | ||
| && self.connections[c].targetIdx < self.totalInputNeuronCount) | ||
| || self.connections[c].sourceIdx == self.connections[c].targetIdx | ||
| ) | ||
| return true; | ||
| self.recursed = []; | ||
| self.inRecursiveCheck = []; | ||
| for(var i=0; i < self.neuronSignals.length; i++) | ||
| { | ||
| self.recursed.push((i < self.totalInputNeuronCount) ? true : false); | ||
| self.inRecursiveCheck.push(false); | ||
| } | ||
| // Get each output node activation recursively | ||
| // NOTE: This is an assumption that genomes have started minimally, and the output nodes lie sequentially after the input nodes | ||
| for (var i = 0; i < self.outputNeuronCount; i++){ | ||
| if(self.recursiveCheckRecursive(self.totalInputNeuronCount + i)) | ||
| { | ||
| // console.log('Returned one!'); | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| }; | ||
| CPPN.prototype.recursiveCheckRecursive = function(currentNode) | ||
| { | ||
| var self = this; | ||
| // console.log('Self recursed : '+ currentNode + ' ? ' + self.recursed[currentNode]); | ||
| // console.log('Checking: ' + currentNode) | ||
| // If we've reached an input node we return since the signal is already set | ||
| if (self.recursed[currentNode]) | ||
| { | ||
| self.inRecursiveCheck[currentNode] = false; | ||
| return false; | ||
| } | ||
| // Mark that the node is currently being calculated | ||
| self.inRecursiveCheck[currentNode] = true; | ||
| // Adjacency list in reverse holds incoming connections, go through each one and activate it | ||
| for (var i = 0; i < self.reverseAdjacentList[currentNode].length; i++) | ||
| { | ||
| var crntAdjNode = self.reverseAdjacentList[currentNode][i]; | ||
| //{ Region recurrant connection handling - not applicable in our implementation | ||
| // If this node is currently being activated then we have reached a cycle, or recurrant connection. Use the previous activation in this case | ||
| if (self.inRecursiveCheck[crntAdjNode]) | ||
| { | ||
| self.inRecursiveCheck[currentNode] = false; | ||
| return true; | ||
| } | ||
| // Otherwise proceed as normal | ||
| else | ||
| { | ||
| var verifiedRecursive; | ||
| // Recurse if this neuron has not been activated yet | ||
| if (!self.recursed[crntAdjNode]) | ||
| verifiedRecursive = self.recursiveCheckRecursive(crntAdjNode); | ||
| if(verifiedRecursive) | ||
| return true; | ||
| } | ||
| //} endregion | ||
| } | ||
| // Mark this neuron as completed | ||
| self.recursed[currentNode] = true; | ||
| // This is no longer being calculated (for cycle detection) | ||
| self.inRecursiveCheck[currentNode] = false; | ||
| return false; | ||
| }; | ||
| (function(exports, selfBrowser, isBrowser){ | ||
| var cppn = {CPPN: {}}; | ||
| //send in the object, and also whetehr or not this is nodejs | ||
| })(typeof exports === 'undefined'? this['cppnjs']['cppn']={}: exports, this, typeof exports === 'undefined'? true : false); |
| /** | ||
| * Module dependencies. | ||
| */ | ||
| //none | ||
| /** | ||
| * Expose `cppnConnection`. | ||
| */ | ||
| module.exports = cppnConnection; | ||
| /** | ||
| * Initialize a new cppnConnection. | ||
| * | ||
| * @param {Number} sourceIdx | ||
| * @param {Number} targetIdx | ||
| * @param {Number} cWeight | ||
| * @api public | ||
| */ | ||
| //simple connection type -- from FloatFastConnection.cs | ||
| function cppnConnection( | ||
| sourceIdx, | ||
| targetIdx, | ||
| cWeight | ||
| ){ | ||
| var self = this; | ||
| self.sourceIdx = sourceIdx; | ||
| self.targetIdx = targetIdx; | ||
| self.weight = cWeight; | ||
| self.signal =0; | ||
| } |
| /** | ||
| * Module dependencies. | ||
| */ | ||
| var NodeType = require("../types/nodeType"); | ||
| /** | ||
| * Expose `cppnNode`. | ||
| */ | ||
| module.exports = cppnNode; | ||
| /** | ||
| * Initialize a new cppnNode. | ||
| * | ||
| * @param {String} actFn | ||
| * @param {String} neurType | ||
| * @param {String} nid | ||
| * @api public | ||
| */ | ||
| function cppnNode(actFn, neurType, nid){ | ||
| var self = this; | ||
| self.neuronType = neurType; | ||
| self.id = nid; | ||
| self.outputValue = (self.neuronType == NodeType.bias ? 1.0 : 0.0); | ||
| self.activationFunction = actFn; | ||
| } |
| var NodeType = | ||
| { | ||
| bias : "Bias", | ||
| input: "Input", | ||
| output: "Output", | ||
| hidden: "Hidden", | ||
| other : "Other" | ||
| }; | ||
| module.exports = NodeType; |
| var utils = {}; | ||
| module.exports = utils; | ||
| utils.stringToFunction = function(str) { | ||
| var arr = str.split("."); | ||
| var fn = (window || this); | ||
| for (var i = 0, len = arr.length; i < len; i++) { | ||
| fn = fn[arr[i]]; | ||
| } | ||
| if (typeof fn !== "function") { | ||
| throw new Error("function not found"); | ||
| } | ||
| return fn; | ||
| }; | ||
| utils.nextDouble = function() | ||
| { | ||
| return Math.random(); | ||
| }; | ||
| utils.next = function(range) | ||
| { | ||
| return Math.floor((Math.random()*range)); | ||
| }; | ||
| utils.tanh = function(arg) { | ||
| // sinh(number)/cosh(number) | ||
| return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg)); | ||
| }; | ||
| utils.sign = function(input) | ||
| { | ||
| if (input < 0) {return -1;} | ||
| if (input > 0) {return 1;} | ||
| return 0; | ||
| }; | ||
| //ROULETTE WHEEL class | ||
| //if we need a node object, this is how we would do it | ||
| // var neatNode = isNodejs ? self['neatNode'] : require('./neatNode.js'); | ||
| utils.RouletteWheel = | ||
| { | ||
| }; | ||
| /// <summary> | ||
| /// A simple single throw routine. | ||
| /// </summary> | ||
| /// <param name="probability">A probability between 0..1 that the throw will result in a true result.</param> | ||
| /// <returns></returns> | ||
| utils.RouletteWheel.singleThrow = function(probability) | ||
| { | ||
| return (utils.nextDouble() <= probability); | ||
| }; | ||
| /// <summary> | ||
| /// Performs a single throw for a given number of outcomes with equal probabilities. | ||
| /// </summary> | ||
| /// <param name="numberOfOutcomes"></param> | ||
| /// <returns>An integer between 0..numberOfOutcomes-1. In effect this routine selects one of the possible outcomes.</returns> | ||
| utils.RouletteWheel.singleThrowEven = function(numberOfOutcomes) | ||
| { | ||
| var probability= 1.0 / numberOfOutcomes; | ||
| var accumulator=0; | ||
| var throwValue = utils.nextDouble(); | ||
| for(var i=0; i<numberOfOutcomes; i++) | ||
| { | ||
| accumulator+=probability; | ||
| if(throwValue<=accumulator) | ||
| return i; | ||
| } | ||
| //throw exception in javascript | ||
| throw "PeannutLib.Maths.SingleThrowEven() - invalid outcome."; | ||
| }; | ||
| /// <summary> | ||
| /// Performs a single thrown onto a roulette wheel where the wheel's space is unevenly divided. | ||
| /// The probabilty that a segment will be selected is given by that segment's value in the 'probabilities' | ||
| /// array. The probabilities are normalised before tossing the ball so that their total is always equal to 1.0. | ||
| /// </summary> | ||
| /// <param name="probabilities"></param> | ||
| /// <returns></returns> | ||
| utils.RouletteWheel.singleThrowArray = function(aProbabilities) | ||
| { | ||
| if(typeof aProbabilities === 'number') | ||
| throw new Error("Send Array to singleThrowArray!"); | ||
| var pTotal=0; // Total probability | ||
| //----- | ||
| for(var i=0; i<aProbabilities.length; i++) | ||
| pTotal+= aProbabilities[i]; | ||
| //----- Now throw the ball and return an integer indicating the outcome. | ||
| var throwValue = utils.nextDouble() * pTotal; | ||
| var accumulator=0; | ||
| for(var j=0; j< aProbabilities.length; j++) | ||
| { | ||
| accumulator+= aProbabilities[j]; | ||
| if(throwValue<=accumulator) | ||
| return j; | ||
| } | ||
| throw "PeannutLib.Maths.singleThrowArray() - invalid outcome."; | ||
| }; | ||
| /// <summary> | ||
| /// Similar in functionality to SingleThrow(double[] probabilities). However the 'probabilities' array is | ||
| /// not normalised. Therefore if the total goes beyond 1 then we allow extra throws, thus if the total is 10 | ||
| /// then we perform 10 throws. | ||
| /// </summary> | ||
| /// <param name="probabilities"></param> | ||
| /// <returns></returns> | ||
| utils.RouletteWheel.multipleThrows = function(aProbabilities) | ||
| { | ||
| var pTotal=0; // Total probability | ||
| var numberOfThrows; | ||
| //----- Determine how many throws of the ball onto the wheel. | ||
| for(var i=0; i<aProbabilities.length; i++) | ||
| pTotal+=aProbabilities[i]; | ||
| // If total probabilty is > 1 then we take this as meaning more than one throw of the ball. | ||
| var pTotalInteger = Math.floor(pTotal); | ||
| var pTotalRemainder = pTotal - pTotalInteger; | ||
| numberOfThrows = Math.floor(pTotalInteger); | ||
| if(utils.nextDouble() <= pTotalRemainder) | ||
| numberOfThrows++; | ||
| //----- Now throw the ball the determined number of times. For each throw store an integer indicating the outcome. | ||
| var outcomes = [];//new int[numberOfThrows]; | ||
| for(var a=0; a < numberOfThrows; a++) | ||
| outcomes.push(0); | ||
| for(var i=0; i<numberOfThrows; i++) | ||
| { | ||
| var throwValue = utils.nextDouble() * pTotal; | ||
| var accumulator=0; | ||
| for(var j=0; j<aProbabilities.length; j++) | ||
| { | ||
| accumulator+=aProbabilities[j]; | ||
| if(throwValue<=accumulator) | ||
| { | ||
| outcomes[i] = j; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return outcomes; | ||
| }; | ||
| utils.RouletteWheel.selectXFromSmallObject = function(x, objects){ | ||
| var ixs = []; | ||
| //works with objects with count or arrays with length | ||
| var gCount = objects.count === undefined ? objects.length : objects.count; | ||
| for(var i=0; i<gCount;i++) | ||
| ixs.push(i); | ||
| //how many do we need back? we need x back. So we must remove (# of objects - x) leaving ... x objects | ||
| for(var i=0; i < gCount -x; i++) | ||
| { | ||
| //remove random index | ||
| ixs.splice(utils.next(ixs.length),1); | ||
| } | ||
| return ixs; | ||
| }; | ||
| utils.RouletteWheel.selectXFromLargeObject = function(x, objects) | ||
| { | ||
| var ixs = []; | ||
| var guesses = {}; | ||
| var gCount = objects.count === undefined ? objects.length : objects.count; | ||
| //we make sure the number of requested objects is less than the object indices | ||
| x = Math.min(x, gCount); | ||
| for(var i=0; i<x; i++) | ||
| { | ||
| var guessIx = utils.next(gCount); | ||
| while(guesses[guessIx]) | ||
| guessIx = utils.next(gCount); | ||
| guesses[guessIx] = true; | ||
| ixs.push(guessIx); | ||
| } | ||
| return ixs; | ||
| }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
0
-100%1
-50%134336
-71.74%2
100%25
-35.9%2899
-65.85%2
100%+ Added
+ Added