//public Axon AddAxon(Nuron input, double weight) //{ // if (input.Level > this.Level) // { // //swaps the nurons if the level is swaped // return input.AddAxon(this, weight); // } // //enshures that the nurons are on diffrent levels // if (input.Level == this.Level) throw new // InvalidOperationException(); // //enshures that the nurons belong to the same network // if (input.network != this.network) throw new // InvalidOperationException(); // //calls upon the internal method // return AddAxonInit(input, weight); //} #endregion //////////////////////////////////////////////////////////////////// #region Internal Methods... /// <summary> /// Connects the given input nuron to the current nuron with the /// given weight. Note that it dose not check the topology of the /// network before adding the axon, so care must be taken to avoid /// redundent connections. If a connection already exists between /// the two nurons, it returns that axon instead. /// </summary> /// <param name="input">Nuron to conect</param> /// <param name="weight">Weight of the connection</param> /// <returns>The axon between the nurons</returns> internal Axon AddAxonInit(NuronOld input, double weight) { ////enshures the nurons belong to the same network //if (network == null || network != input.network) // throw new InvalidOperationException(); //makes shure our parent network hasn't been disposed if (network == null) { throw new InvalidOperationException(); } //sees if we alreay contain a link to the input Axon ax = GetAxon(input.Index); if (ax == null) { //obtains an index to the sorce and target int source = this.Index; int target = input.Index; //creates the axon and adds it to our list ax = new Axon(source, target, weight); inputs.Add(ax); } else { //sets the axons weight to our new weight ax.Weight = weight; } return(ax); }
/// <summary> /// Compares the current genotype to the genotype of a diffrent /// nural net. The result is a positive real value that indicates /// how siimilar the genotypes are. This is tipicaly used to /// seperate a population of individules into species. /// </summary> /// <param name="other">Nural net for comparison</param> /// <returns>Mesure of similarity</returns> public double Compare(NetworkCPP other) { //used in computing the distance int match = 0; int disjoint = 0; double wbar = 0.0; //lists the axons in each of the networks var ittr1 = this.ListAxons(); var ittr2 = other.ListAxons(); foreach (Axon ax1 in ittr1) { //tries to find the matching axon Axon ax2 = other.FindMatch(ax1); if (ax2 != null) { //computes the distance between the weights double w1 = ax1.Weight; double w2 = ax2.Weight; wbar += Math.Abs(w1 - w2); match += 1; } else { //counts the disjoint nodes disjoint += 1; } } foreach (Axon ax1 in ittr2) { //only counts the missing disjoint edges Axon ax2 = other.FindMatch(ax1); if (ax2 == null) { disjoint += 1; } } //determins the size of the larger network int size = Math.Max(this.Axons, other.Axons); size = (size > 20) ? size - 20 : 1; //couputes the distance for specisation double dist = (C0 * disjoint) / (double)size; dist += C1 * (wbar / (double)match); return(dist); }
/// <summary> /// Helper method: Finds an axon in the curent network that matches a /// target axon from another network. If no sucth match can be found, /// it returns null instead. /// </summary> /// <param name="other">Target axon</param> /// <returns>A matching axon</returns> private Axon FindMatch(Axon other) { //first atempts to find the target nuron NuronOld n1 = nurons.GetValue(other.Target); if (n1 == null) { return(null); } //obtains the axon from the target return(n1.GetAxon(other.Source)); }
/// <summary> /// Expands the curent nural net, in place, by either inserting a /// new node along a pre-existing edge or creating a new edge. The /// probibility of either event occoring is determined by the /// existing topology. /// </summary> public void ExpandSelf() { NuronOld n1, n2; //generates a pair of random nurons bool test = RandPair(out n1, out n2); Axon target = n2.GetAxon(n1.Index); if (test && target == null) { //creates a new axon between the nurons double weight = rng.RandGauss() * SDN; n2.AddAxonInit(n1, weight); } else if (test && !target.Enabled) { //reinitilises the axon with a new weight target.Weight = rng.RandGauss() * SDN; target.Enabled = true; } else if ((n2.Level - n1.Level) > 3) { //disables the target edge double weight = target.Weight; target.Enabled = false; //creates a new node with a random funciton int index = RandIndex(); int level = (n2.Level + n1.Level) / 2; ActFunc func = RandFunc(); //aborts the operation if we fail to insert if (index < 0) { return; } //inserts the node into our data-structor NuronOld nx = new NuronOld(this, func, level, index); nurons.Add(index, nx); //adds axons to replace the missing axon nx.AddAxonInit(n1, 1.0); n2.AddAxonInit(nx, weight); } }
/// <summary> /// Combines the genes of the curent nural net with the genes of /// another network to create a brand new offspring. The idea is /// that the child network will possess trates from both its /// parents, similar to sexual reproduction. /// </summary> /// <param name="rng">Random number generator</param> /// <param name="mate">Mate of the curent network</param> /// <returns>The child of both networks</returns> public NetworkCPP Combine(VRandom rng, NetworkCPP mate) { //makes a clone of the dominate parent NetworkCPP child = new NetworkCPP(rng, this); //determins weather or not to do liniar crossover bool liniar = rng.RandBool(P_Linear); double a = rng.NextDouble(); //lists all the axons in the mate var axons = mate.ListAxons(); foreach (Axon ax in axons) { //obtains the matching child axon Axon axc = child.FindMatch(ax); if (axc == null) { continue; } if (liniar) { //chooses a value between the two weights double weight = axc.Weight * (1.0 - a); axc.Weight = weight + (ax.Weight * a); } else { //determins the new weight based on crossover bool cross = rng.RandBool(); if (cross) { axc.Weight = ax.Weight; } } //has a chance of enabling if either are disabled bool en = ax.Enabled && axc.Enabled; axc.Enabled = en || rng.RandBool(0.25); } return(child); }
/// <summary> /// Creates a copy of a given nuron for a given network. All of the /// refrences to axons in the old network, now point to axons in /// the new network. All other values remain the same. /// </summary> /// <param name="network">The network containing this nuron</param> /// <param name="other">Another neuron to copy its values</param> internal NuronOld(NetworkCPP network, NuronOld other) { //sets the network refrence to the new network this.network = network; //copies the other vlaues func = other.func; level = other.level; value = other.value; inputs = new VListArray <Axon>(other.inputs.Count); //makes a deep copy of the list of inputs foreach (Axon ax in other.inputs) { Axon clone = new Axon(ax); this.inputs.Add(clone); } }