/// <summary> /// Sample from the provided discrete probability distribution. /// </summary> /// <param name="dist">The discrete distribution to sample from.</param> /// <param name="rng">Random number generator.</param> public static int Sample(DiscreteDistribution dist, XorShiftRandom rng) { // Throw the ball and return an integer indicating the outcome. double sample = rng.NextDouble(); double acc = 0.0; for(int i=0; i<dist.Probabilities.Length; i++) { acc += dist.Probabilities[i]; if(sample < acc) { return dist.Labels[i]; } } // We might get here through floating point arithmetic rounding issues. // e.g. accumulator == throwValue. // Find a nearby non-zero probability to select. // Wrap around to start of array. for(int i=0; i<dist.Probabilities.Length; i++) { if(0.0 != dist.Probabilities[i]) { return dist.Labels[i]; } } // If we get here then we have an array of zero probabilities. throw new InvalidOperationException("Invalid operation. No non-zero probabilities to select."); }
/// <summary> /// Constructs an activation function library with the provided list of activation functions. /// </summary> public DefaultActivationFunctionLibrary(IList<ActivationFunctionInfo> fnList) { // Build a RouletteWheelLayout based on the selection probability on each item. int count = fnList.Count; double[] probabilities = new double[count]; for(int i=0; i<count; i++) { probabilities[i] = fnList[i].SelectionProbability; } _rwl = new DiscreteDistribution(probabilities); _functionList = fnList; // Build a dictionary of functions keyed on integer ID. _functionDict = CreateFunctionDictionary(_functionList); }
/// <summary> /// Copy constructor. /// </summary> public DiscreteDistribution(DiscreteDistribution copyFrom) { _probArr = (double[])copyFrom._probArr.Clone(); _labelArr = (int[])copyFrom._labelArr.Clone(); }
/// <summary> /// Construct with default set of parameters. /// </summary> public NeatGenomeParameters() { _activationFn = SteepenedSigmoid.__DefaultInstance; _connectionWeightRange = DefaultConnectionWeightRange; _initialInterconnectionsProportion = DefaultInitialInterconnectionsProportion; _disjointExcessGenesRecombineProbability = DefaultDisjointExcessGenesRecombineProbability; _connectionWeightMutationProbability = DefaultConnectionWeightMutationProbability; _addNodeMutationProbability = DefaultAddNodeMutationProbability; _addConnectionMutationProbability = DefaultAddConnectionMutationProbability; _nodeAuxStateMutationProbability = DefaultNodeAuxStateMutationProbability; _deleteConnectionMutationProbability = DefaultDeleteConnectionMutationProbability; _rouletteWheelLayout = CreateRouletteWheelLayout(); _rouletteWheelLayoutNonDestructive = CreateRouletteWheelLayout_NonDestructive(); // Create a connection weight mutation scheme. _connectionMutationInfoList = CreateConnectionWeightMutationScheme_Default(); // No fitness history. _fitnessHistoryLength = 0; }
/// <summary> /// Copy constructor. /// </summary> public NeatGenomeParameters(NeatGenomeParameters copyFrom) { _feedforwardOnly = copyFrom._feedforwardOnly; _activationFn = copyFrom._activationFn; _connectionWeightRange = copyFrom._connectionWeightRange; _initialInterconnectionsProportion = copyFrom._initialInterconnectionsProportion; _disjointExcessGenesRecombineProbability = copyFrom._disjointExcessGenesRecombineProbability; _connectionWeightMutationProbability = copyFrom._connectionWeightMutationProbability; _addNodeMutationProbability = copyFrom._addNodeMutationProbability; _addConnectionMutationProbability = copyFrom._addConnectionMutationProbability; _nodeAuxStateMutationProbability = copyFrom._nodeAuxStateMutationProbability; _deleteConnectionMutationProbability = copyFrom._deleteConnectionMutationProbability; _rouletteWheelLayout = new DiscreteDistribution(copyFrom._rouletteWheelLayout); _rouletteWheelLayoutNonDestructive = new DiscreteDistribution(copyFrom._rouletteWheelLayoutNonDestructive); _connectionMutationInfoList = new ConnectionMutationInfoList(copyFrom._connectionMutationInfoList); _connectionMutationInfoList.Initialize(); _fitnessHistoryLength = copyFrom._fitnessHistoryLength; }
/// <summary> /// Move the prey. The prey moves by a simple set of stochastic rules that make it more likely to move away from /// the agent, and more so when it is close. /// </summary> public void MovePrey() { // Determine if prey will move in this timestep. (Speed is simulated stochastically) if(_rng.NextDouble() > _preySpeed) { return; } // Determine position of agent relative to prey. PolarPoint relPolarPos = PolarPoint.FromCartesian(_agentPos - _preyPos); // Calculate probabilities of moving in each of the four directions. This stochastic strategy is taken from: // Incremental Evolution Of Complex General Behavior, Faustino Gomez and Risto Miikkulainen (1997) // (http://nn.cs.utexas.edu/downloads/papers/gomez.adaptive-behavior.pdf) // Essentially the prey moves randomly but we bias the movements so the prey moves away from the agent, and thus // generally avoids getting eaten through stupidity. double T = MovePrey_T(relPolarPos.Radial); double[] probs = new double[4]; probs[0] = Math.Exp((CalcAngleDelta(relPolarPos.Theta, Math.PI/2.0) / Math.PI) * T * 0.33); // North. probs[1] = Math.Exp((CalcAngleDelta(relPolarPos.Theta, 0) / Math.PI) * T * 0.33); // East. probs[2] = Math.Exp((CalcAngleDelta(relPolarPos.Theta, Math.PI * 1.5) / Math.PI) * T * 0.33); // South. probs[3] = Math.Exp((CalcAngleDelta(relPolarPos.Theta, Math.PI) / Math.PI) * T * 0.33); // West. DiscreteDistribution rwl = new DiscreteDistribution(probs); int action = DiscreteDistributionUtils.Sample(rwl, _rng); switch(action) { case 0: // Move north. _preyPos._y = Math.Min(_preyPos._y + 1, _gridSize - 1); break; case 1: // Move east. _preyPos._x = Math.Min(_preyPos._x + 1, _gridSize - 1); break; case 2: // Move south. _preyPos._y = Math.Max(_preyPos._y - 1, 0); break; case 3: // Move west (is the best?) _preyPos._x = Math.Max(_preyPos._x - 1, 0); break; } }