Guest User

NEATNet.cs

a guest
Mar 8th, 2017
883
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 51.99 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System.Collections;
  3. using UnityEngine;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7.  
  8. public class Neuron
  9. {
  10. public int id;
  11. public float value;
  12. public List<NEATGene> incomming = new List<NEATGene>();
  13. public NEATGene[] incommingArray;
  14.  
  15. public Neuron(int id, float value)
  16. {
  17. this.id = id;
  18. this.value = value;
  19. }
  20. }
  21.  
  22. /// <summary>
  23. /// Handels mutation, crossover, specification, feedforward activation and creation of neural network's genotype.
  24. /// </summary>
  25. public class NEATNet {
  26.  
  27. // ADDING GENE NETWORK TO NEURAL NETWORK CONVERSION USED IN LSES VERSON 2
  28. //------------------------------------------------
  29. private List<Neuron> network;
  30. private Neuron[] networkArray;
  31. private int usedHiddenNeuronIndex;
  32.  
  33. public void GenerateNeuralNetworkFromGenome()
  34. {
  35. network = new List<Neuron>();
  36.  
  37. usedHiddenNeuronIndex = int.MinValue;
  38. for (int i = 0; i < geneList.Count; i++)
  39. {
  40. int inNode = geneList[i].GetInID();
  41. int outNode = geneList[i].GetOutID();
  42.  
  43. if (usedHiddenNeuronIndex < inNode)
  44. usedHiddenNeuronIndex = inNode;
  45.  
  46. if (usedHiddenNeuronIndex < outNode)
  47. usedHiddenNeuronIndex = outNode;
  48. }
  49.  
  50. usedHiddenNeuronIndex = usedHiddenNeuronIndex + 1; //incremented as per LSES algorithm
  51.  
  52.  
  53. for (int i = 0; i < usedHiddenNeuronIndex; i++)
  54. {
  55. Neuron neuron = new Neuron(i, 0f);
  56. network.Add(neuron);
  57. }
  58.  
  59. network.Sort((x, y) => x.id.CompareTo(y.id));
  60. geneList.Sort((x, y) => x.GetOutID().CompareTo(y.GetOutID()));
  61.  
  62.  
  63. for (int i = 0; i < geneList.Count; i++)
  64. {
  65. NEATGene gene = geneList[i];
  66.  
  67. if (gene.GetGeneState() == true)
  68. {
  69. network[gene.GetOutID()].incomming.Add(gene);
  70. }
  71. }
  72.  
  73. networkArray = network.ToArray();
  74.  
  75. for (int i = 0; i < networkArray.Length; i++)
  76. {
  77. networkArray[i].incomming.Sort((x, y) => x.GetInID().CompareTo(y.GetInID()));
  78. networkArray[i].incommingArray = networkArray[i].incomming.ToArray();
  79. }
  80.  
  81.  
  82. geneList.Sort((x, y) => x.GetInnovation().CompareTo(y.GetInnovation())); //reset back to sorted interms of innovation number
  83. }
  84.  
  85. public float[] FireNet(float[] inputs)
  86. {
  87. for (int i = 0; i < inputs.Length; i++)
  88. {
  89. networkArray[i].value = inputs[i];
  90.  
  91. }
  92. float[] output = new float[numberOfOutputs];
  93.  
  94. float[] tempValues = new float[networkArray.Length];
  95. for (int i = 0; i < tempValues.Length; i++)
  96. tempValues[i] = networkArray[i].value;
  97.  
  98. networkArray[numberOfInputs - 1].value = 1f;
  99.  
  100. for (int i = 0; i < networkArray.Length; i++)
  101. {
  102. float value = 0;
  103. Neuron neuron = networkArray[i];
  104. NEATGene[] incommingArray = neuron.incommingArray;
  105.  
  106. if (incommingArray.Length > 0)
  107. {
  108. for (int j = 0; j < incommingArray.Length; j++)
  109. {
  110. if (incommingArray[j].GetGeneState() == true)
  111. {
  112. value = value + (incommingArray[j].GetWeight() * tempValues[incommingArray[j].GetInID()]);
  113. }
  114. }
  115. neuron.value = (float)System.Math.Tanh(value);
  116. }
  117. }
  118.  
  119.  
  120.  
  121. for (int i = 0; i < output.Length; i++)
  122. {
  123. output[i] = networkArray[i + numberOfInputs].value;
  124.  
  125. }
  126.  
  127. return output;
  128. }
  129.  
  130.  
  131. //------------------------------------------------
  132.  
  133.  
  134. private NEATConsultor consultor; //Handles consultor genome sequence
  135.  
  136. private List<NEATGene> geneList; //list of the genome sequence for this neural network
  137. private List<NEATNode> nodeList; //list of nodes for this neural network
  138.  
  139. private int numberOfInputs; //Number of input perceptrons of neural network (including bias)
  140. private int numberOfOutputs; //Number of output perceptrons
  141. private int[] netID = new int[2]; //ID of this neural network
  142.  
  143. private float time; //time to run test on this neural network
  144. private float timeLived; //time the neural network actually lived in the test enviroment
  145. private float netFitness; //fitness of this neural network
  146.  
  147. /// <summary>
  148. /// This is a deep copy constructor.
  149. /// Creating neural network structure from deep copying another network
  150. /// </summary>
  151. /// <param name="copy">Neural network to deep copy</param>
  152. public NEATNet(NEATNet copy) {
  153. this.consultor = copy.consultor; //shallow copy consultor
  154. this.numberOfInputs = copy.numberOfInputs; //copy number of inputs
  155. this.numberOfOutputs = copy.numberOfOutputs; //copy number of outputs
  156.  
  157. CopyNodes(copy.nodeList); //deep copy node list
  158. CopyGenes(copy.geneList); //deep copy gene list
  159.  
  160. this.netID = new int[2]; //reset ID
  161. this.time = 0f; //reset time
  162. this.netFitness = 0f; //reset fitness
  163. this.timeLived = 0f; //reset time lived
  164. }
  165.  
  166. /// <summary>
  167. /// Creating neural network structure using neat packet from database
  168. /// </summary>
  169. /// <param name="packet">Neat packet received from database</param>
  170. /// <param name="consultor">Consultor with master genome and specification information</param>
  171. public NEATNet(NEATPacket packet, NEATConsultor consultor) {
  172. this.consultor = consultor; //shallow copy consultor
  173. this.numberOfInputs = packet.node_inputs; //copy number of inputs
  174. this.numberOfOutputs = packet.node_outputs; //copy number of outputs
  175.  
  176. int numberOfNodes = packet.node_total; //number of nodes in the network from database
  177. int numberOfgenes = packet.gene_total; //number of genes in the network from database
  178. int informationSize = NEATGene.GENE_INFORMATION_SIZE; //size of genome information
  179.  
  180. geneList = new List<NEATGene>(); //create an empty gene list
  181.  
  182. InitilizeNodes(); //initialize initial nodes
  183.  
  184. for (int i = numberOfInputs + numberOfOutputs; i < numberOfNodes; i++) { //run through the left over nodes, since (numberOfInputs + numberOfOutputs) where created by initilize node method
  185. NEATNode node = new NEATNode(i, NEATNode.HIDDEN_NODE); //create node with index i as id and will be hidden node
  186. nodeList.Add(node); //add node to node list
  187. }
  188.  
  189. float[] geneInformation = packet.genome.Split('_').Select(x => float.Parse(x)).ToArray(); //using Linq libary and delimiters, parse and spilt string genome from neat packet into float array
  190.  
  191. for (int i = 0; i < geneInformation.Length; i+=informationSize) { //run through all gene information, 4 information make up 1 gene, thus increment by 4
  192. int inno = this.consultor.CheckGeneExistance((int)geneInformation[i], (int)geneInformation[i + 1]); //check if this gene exists in the consultor
  193. NEATGene gene = new NEATGene(inno, (int)geneInformation[i], (int)geneInformation[i + 1], geneInformation[i + 2], geneInformation[i + 3] == 1.0? true:false); //create gene
  194. geneList.Add(gene); //add gene to the gene list
  195. }
  196.  
  197. this.netID = new int[2]; //reset ID
  198. this.time = 0f; //reset time
  199. this.netFitness = 0f; //reset fitness
  200. this.timeLived = 0f; //reset time lived
  201. }
  202.  
  203. /// <summary>
  204. /// Creating a primitive network structure (every input connect to every output) from provided parameters
  205. /// </summary>
  206. /// <param name="consultor">Consultor with master genome and specification information</param>
  207. /// <param name="netID">ID of the network</param>
  208. /// <param name="numberOfInputs">Number of input perceptrons</param>
  209. /// <param name="numberOfOutputs">Number of output perceptrons</param>
  210. /// <param name="time">Time to test the network</param>
  211. public NEATNet(NEATConsultor consultor, int[] netID, int numberOfInputs, int numberOfOutputs, float time) {
  212. this.consultor = consultor; //shallow copy consultor
  213. this.netID = new int[] {netID[0], netID[1]}; //copy ID
  214. this.numberOfInputs = numberOfInputs; //copy number of inputs
  215. this.numberOfOutputs = numberOfOutputs; //copy number of outputs
  216. this.time = time; //copy time to test
  217.  
  218. this.netFitness = 0f; //reset net fitness
  219. this.timeLived = 0f; //reset time lived
  220.  
  221. InitilizeNodes(); //initialize initial nodes
  222. InitilizeGenes(); //initialize initial gene sequence
  223. }
  224.  
  225. /// <summary>
  226. /// Creating an already designed network structure from given node and gene lists
  227. /// </summary>
  228. /// <param name="consultor">Consultor with master genome and specification information</param>
  229. /// <param name="numberOfInputs">Number of input perceptrons</param>
  230. /// <param name="numberOfOutputs">Number of output perceptrons</param>
  231. /// <param name="copyNodes">Node list to deep copy</param>
  232. /// <param name="copyGenes">Gene list to deep copy</param>
  233. public NEATNet(NEATConsultor consultor, int numberOfInputs, int numberOfOutputs, List<NEATNode> copyNodes, List<NEATGene> copyGenes) {
  234. this.consultor = consultor; //shallow copy consultor
  235. this.numberOfInputs = numberOfInputs; //copy number of inputs
  236. this.numberOfOutputs = numberOfOutputs; //copy number of outputs
  237.  
  238. CopyNodes(copyNodes); //deep copy node list
  239. CopyGenes(copyGenes); //deep copy gene list
  240.  
  241. this.netID = new int[2]; //reset ID
  242. this.time = 0f; //reset time
  243. this.netFitness = 0f; //reset fitness
  244. this.timeLived = 0f; //reset time lived
  245. }
  246.  
  247. /// <summary>
  248. /// Initilizing initial node list with given number of input perceptrons which includes the bias node
  249. /// </summary>
  250. private void InitilizeNodes() {
  251. nodeList = new List<NEATNode>(); //create an empty node list
  252.  
  253. NEATNode node = null;
  254.  
  255. for (int i = 0; i < numberOfInputs; i++) { //run through number of input perceptrons
  256.  
  257. if(i == (numberOfInputs - 1)) //if this is the last input
  258. node = new NEATNode(i,NEATNode.INPUT_BIAS_NODE); //make it a input bias type node with index i as node ID
  259. else //if this is not the last input
  260. node = new NEATNode(i, NEATNode.INPUT_NODE); //make it a input type node with index i as node ID
  261.  
  262. nodeList.Add(node); //add node to the node list
  263. }
  264.  
  265. for (int i = numberOfInputs; i < numberOfInputs+numberOfOutputs; i++){ //run through number of output perceptrons
  266. node = new NEATNode(i, NEATNode.OUTPUT_NODE); //make it a putput type node with index i as node ID
  267. nodeList.Add(node); //add node to the node list
  268. }
  269. }
  270.  
  271. /// <summary>
  272. /// Initilizing initial gene list with given number of input and output perceptrons to create a primitive genome (all inputs connected to all outputs)
  273. /// </summary>
  274. private void InitilizeGenes() {
  275. geneList = new List<NEATGene>(); //create an empty gene list
  276.  
  277. for (int i = 0; i < numberOfInputs; i++){ //run through number of inputs
  278. for (int j = numberOfInputs; j < numberOfInputs+numberOfOutputs; j++){ //run through number of outputs
  279. int inno = consultor.CheckGeneExistance(i,j); //check if gene exists in consultor
  280. NEATGene gene = new NEATGene(inno, i, j, Random.Range(-1f,1f), true); // create gene with default weight of 1.0 and and is active
  281.  
  282. InsertNewGene(gene); //insert gene to correct location in gene list
  283. }
  284. }
  285. }
  286.  
  287. /// <summary>
  288. /// Returns the fitness of this network
  289. /// </summary>
  290. /// <returns>Fitness</returns>
  291. public float GetNetFitness() {
  292. return netFitness; //reutrn fitness
  293. }
  294.  
  295. /// <summary>
  296. /// Returns the time this network has lived
  297. /// </summary>
  298. /// <returns>Time lived</returns>
  299. public float GetTimeLived() {
  300. return timeLived; //return time lived
  301. }
  302.  
  303. /// <summary>
  304. /// Set ID of the network
  305. /// </summary>
  306. /// <param name="netID">Network ID to set</param>
  307. public void SetNetID(int[] netID) {
  308. this.netID = new int[] {netID[0], netID[1]}; //set ID
  309. }
  310.  
  311. /// <summary>
  312. /// Set fitness to given fitness
  313. /// </summary>
  314. /// <param name="netFitness">Fitness to set network fitness to</param>
  315. public void SetNetFitness(float netFitness) {
  316. this.netFitness = netFitness; //set fitness
  317. }
  318.  
  319. /// <summary>
  320. /// Add given fitness to the current fitness
  321. /// </summary>
  322. /// <param name="netFitness">Fitness to add</param>
  323. public void AddNetFitness(float netFitness) {
  324. this.netFitness += netFitness; //increment by given fitness
  325. }
  326.  
  327. /// <summary>
  328. /// Set time lived of this network
  329. /// </summary>
  330. /// <param name="timeLived">Time lived to set</param>
  331. public void SetTimeLived(float timeLived) {
  332. this.timeLived = timeLived; //set time lived
  333. }
  334.  
  335. /// <summary>
  336. /// Add given time lived to current time lived
  337. /// </summary>
  338. /// <param name="timeLived">Time lived to add</param>
  339. public void AddTimeLived(float timeLived) {
  340. this.timeLived += timeLived; //increment by given time lived
  341. }
  342.  
  343. /// <summary>
  344. /// Return ID of this network
  345. /// </summary>
  346. /// <returns>ID of this network</returns>
  347. public int[] GetNetID() {
  348. return netID; //return network ID
  349. }
  350.  
  351. /// <summary>
  352. /// Return test time of this network
  353. /// </summary>
  354. /// <returns>Test time</returns>
  355. public float GetTestTime() {
  356. return time; //return test time
  357. }
  358.  
  359. /// <summary>
  360. /// Return total number of nodes (perceptrons) in this network
  361. /// </summary>
  362. /// <returns>Number of total nodes</returns>
  363. public int GetNodeCount() {
  364. return nodeList.Count; //return node code
  365. }
  366.  
  367. /// <summary>
  368. /// Return number of genes in the genome
  369. /// </summary>
  370. /// <returns>Number of genes in the genome</returns>
  371. public int GetGeneCount() {
  372. return geneList.Count; //gene count
  373. }
  374.  
  375. /// <summary>
  376. /// Return number of input perceptrons
  377. /// </summary>
  378. /// <returns>Number of input nodes</returns>
  379. public int GetNumberOfInputNodes() {
  380. return numberOfInputs; //return number of inputs
  381. }
  382.  
  383. /// <summary>
  384. /// Return number of output perceptrons
  385. /// </summary>
  386. /// <returns>Number of output nodes</returns>
  387. public int GetNumberOfOutputNodes() {
  388. return numberOfOutputs; //return number of outputs
  389. }
  390.  
  391. /// <summary>
  392. /// Return consultor of this network
  393. /// </summary>
  394. /// <returns>Consultor</returns>
  395. public NEATConsultor GetConsultor() {
  396. return consultor; //return consultor
  397. }
  398.  
  399. /// <summary>
  400. /// Set test time to given time
  401. /// </summary>
  402. /// <param name="time">Test time</param>
  403. public void SetTestTime(float time) {
  404. this.time = time; //set test time
  405. }
  406.  
  407. /// <summary>
  408. /// Compile and return gene connections information which include weight, in node, and out node in a 2D array
  409. /// </summary>
  410. /// <returns>Array of gene connections information in a 2D array</returns>
  411. public float[][] GetGeneDrawConnections() {
  412. int numberOfGenes = geneList.Count; //copy gene count
  413.  
  414. float[][] connections = null; //2D connections to return
  415.  
  416. List<float[]> connectionList = new List<float[]>(); //empty connections list to fill with genome details
  417.  
  418. for (int i = 0; i < numberOfGenes; i++) { //run through all genes
  419. NEATGene gene = geneList[i]; // get gene at index i
  420.  
  421. float[] details = new float[3]; //will copy in node ID, out node ID and weight
  422.  
  423. details[0] = gene.GetInID(); //copy in node ID
  424. details[1] = gene.GetOutID(); //copy out node ID
  425.  
  426. if (gene.GetGeneState() == true) //gene is enabled
  427. details[2] = gene.GetWeight(); //copy weight
  428. else //gene is disabled
  429. details[2] = 0f; //set to 0
  430.  
  431. connectionList.Add(details); //add detail to the connection list
  432. }
  433.  
  434. connections = connectionList.ToArray(); //convert connection list to 2D connection array
  435. return connections; //return 2D connection array
  436. }
  437.  
  438. /// <summary>
  439. /// Compile and return genome in a large string to be saved in a database
  440. /// </summary>
  441. /// <returns>Genome string</returns>
  442. public string GetGenomeString() {
  443. string genome = ""; //genome to return
  444. int numberOfGenes = geneList.Count; //get number of genes
  445.  
  446. for (int i = 0; i < numberOfGenes; i++) { //run through all genes
  447. NEATGene gene = geneList[i]; //get gene at index i
  448. genome += gene.GetGeneString(); //concatenate gene string to genome
  449.  
  450. if (i < numberOfGenes - 1) { //if this is not the last index
  451. genome += "_"; //add seperation underscore to seperate 2 different genomes
  452. }
  453. }
  454.  
  455. return genome; //return string genome
  456. }
  457.  
  458. /// <summary>
  459. /// Change network's input perceptron values to the given input array
  460. /// </summary>
  461. /// <param name="inputs">Replacing input perceptron values with this array</param>
  462. public void SetInputValues(float[] inputs) {
  463. for (int i = 0; i < numberOfInputs; i++) { //run through number of inputs
  464. if (nodeList[i].GetNodeType() == NEATNode.INPUT_NODE) { //only if this is a input node
  465. nodeList[i].SetValue(inputs[i]); //change value of node to given value at index i
  466. }
  467. else { //if this is not an input type node
  468. break;
  469. }
  470. }
  471. }
  472.  
  473. /// <summary>
  474. /// Compile and return all node values in an array
  475. /// </summary>
  476. /// <returns>All node values in an array</returns>
  477. private float[] GetAllNodeValues() {
  478. float[] values = new float[nodeList.Count]; //create an array with the szie of number of nodes
  479.  
  480. for (int i = 0; i < values.Length; i++){ //run through number of nodes
  481. values[i] = nodeList[i].GetValue(); //set node values
  482. }
  483. return values; //return all nodes value array
  484. }
  485.  
  486. /// <summary>
  487. /// Compile and return only input node values in an array
  488. /// </summary>
  489. /// <returns>Only input node values in an array</returns>
  490. private float[] GetInputValues(){
  491. float[] values = new float[numberOfInputs]; //create an array with size of number of input nodes
  492.  
  493. for (int i = 0; i < numberOfInputs; i++){ //run through number of inputs
  494. values[i] = nodeList[i].GetValue(); //set input nodes value
  495. }
  496.  
  497. return values; //return input nodes value array
  498. }
  499.  
  500. /// <summary>
  501. /// Compile and return only output node values in an array
  502. /// </summary>
  503. /// <returns>Only ouput node values in an array</returns>
  504. public float[] GetOutputValues(){
  505. float[] values = new float[numberOfOutputs]; //create an array with size of number of output nodes
  506.  
  507. for (int i = 0; i < numberOfOutputs; i++) { //run through number of outputs
  508. values[i] = nodeList[i + numberOfInputs].GetValue(); //set output nodes value
  509. }
  510.  
  511. return values; //return output nodes value array
  512. }
  513.  
  514. /// <summary>
  515. /// Compile and return only hidden node values in an array
  516. /// </summary>
  517. /// <returns>Only hidden node values in an array</returns>
  518. private float[] GetHiddenValues(){
  519. int numberOfHiddens = nodeList.Count - (numberOfInputs + numberOfOutputs); //get number of hidden nodes that exist
  520. float[] values = new float[numberOfHiddens]; //create an array with size of number of hidden nodes
  521.  
  522. for (int i = 0; i < numberOfHiddens; i++){ //run through number of hiddens
  523. values[i] = nodeList[i + numberOfInputs + numberOfOutputs].GetValue(); //set hidden nodes value
  524. }
  525.  
  526. return values; //return hidden nodes value array
  527. }
  528.  
  529. /// <summary>
  530. /// Create node list from deep copying a given node list
  531. /// </summary>
  532. /// <param name="copyNodes">Node list to deep copy</param>
  533. private void CopyNodes(List<NEATNode> copyNodes) {
  534. nodeList = new List<NEATNode>(); //create an empty node list
  535. int numberOfNodes = copyNodes.Count; //number of nodes to copy
  536.  
  537. for (int i = 0; i < numberOfNodes; i++) { //run through number of nodes to copy
  538. NEATNode node = new NEATNode(copyNodes[i]); //create deep copy of node at index i
  539. nodeList.Add(node); //add node to node list
  540. }
  541. }
  542.  
  543. /// <summary>
  544. /// Create gene list from deep copying a given gene list
  545. /// </summary>
  546. /// <param name="copyGenes">Gene list to deep copy</param>
  547. private void CopyGenes(List<NEATGene> copyGenes) {
  548. geneList = new List<NEATGene>(); //create an empty node list
  549. int numberOfGenes = copyGenes.Count; //number of nodes to copy
  550.  
  551. for (int i = 0; i < numberOfGenes; i++) { //run through number of genes to copy
  552. NEATGene gene = new NEATGene(copyGenes[i]); //create deep copy of gene at index i
  553. geneList.Add(gene); //add gene to gene list
  554. }
  555. }
  556.  
  557. /// <summary>
  558. /// Feed-forward the neural network by creating a temporary phenotype from the genotype
  559. /// </summary>
  560. /// <param name="inputs">Inputs to set as the input perceptron values</param>
  561. /// <returns>An array of output values after feed-forward</returns>
  562. public float[] FireNet_OLD(float[] inputs){
  563. int numberOfGenes = geneList.Count; //get number of genes
  564.  
  565. SetInputValues(inputs); //set input values to the input nodes
  566.  
  567. //set all output node values to 0
  568. for (int i = 0; i < numberOfOutputs; i++){ //run through number of outputs
  569. //nodeList[i + numberOfInputs].SetValue(0f);
  570. }
  571.  
  572. //feed forward reccurent net
  573. float[] tempValues = GetAllNodeValues(); //create a temporary storage of previous node values (used as a phenotype)
  574.  
  575. for (int i = 0; i < numberOfGenes; i++) { //run through number of genes
  576. NEATGene gene = geneList[i]; //get gene at index i
  577. bool on = gene.GetGeneState(); //get state of the gene
  578.  
  579. if (on == true) { //if gene is active
  580. int inID = gene.GetInID(); //get in node ID
  581. int outID = gene.GetOutID(); //get out node ID
  582. float weight = gene.GetWeight(); //get weight of the connection
  583.  
  584. NEATNode outNode = nodeList[outID]; //get out node
  585.  
  586. float inNodeValue = tempValues[inID]; //get in node's value
  587. float outNodeValue = tempValues[outID]; //get out node's value
  588.  
  589. float newOutNodeValue = outNodeValue + (inNodeValue*weight); //calculate new out node's value
  590. outNode.SetValue(newOutNodeValue); //set new value to the out node
  591. }
  592. }
  593.  
  594. //Activation
  595. for (int i = 0; i < nodeList.Count; i++) { //run through number of nodes
  596. nodeList[i].Activation(); //provide an activation function over all nodes
  597. }
  598.  
  599. return GetOutputValues(); //return output
  600. }
  601.  
  602. /// <summary>
  603. /// Mutating this neural network
  604. /// </summary>
  605. public void Mutate() {
  606. int randomNumber = Random.Range(1, 101); //random number between 1 and 100
  607. int chance = 25; //25% chance of mutation
  608.  
  609. if (randomNumber <= chance) { //random number is below chance
  610. AddConnection(); //add connection between 2 nodes
  611. }
  612. else if (randomNumber <= (chance*2)) {//random number is below chance*2
  613. AddNode(); //add a new node bettwen an existing connection
  614. }
  615.  
  616. MutateWeight(); //mutate weight
  617.  
  618.  
  619. }
  620.  
  621. /// <summary>
  622. /// Adding a connection between 2 previously unconnected nodes (except no inputs shall ever connect to other inputs)
  623. /// </summary>
  624. private void AddConnection(){
  625. int randomNodeID1, randomNodeID2, inno; //random node ID's and innovation number
  626. int totalAttemptsAllowed = (int)Mathf.Pow(nodeList.Count,2); //total attempts allowed to find two unconnected nodes
  627.  
  628. bool found = false; //used to check if a connection is found
  629.  
  630. while (totalAttemptsAllowed > 0 && found == false) { //if connection is found and greater than 0 attempts left
  631. randomNodeID1 = Random.Range(0, nodeList.Count); //pick a random node
  632. randomNodeID2 = Random.Range(numberOfInputs, nodeList.Count); //pick a random node that is not the input
  633.  
  634. if (!ConnectionExists(randomNodeID1, randomNodeID2)) { //if connection does not exist with random node 1 as in node and random node 2 and out node
  635. inno = consultor.CheckGeneExistance(randomNodeID1, randomNodeID2); //get the new innovation number
  636. NEATGene gene = new NEATGene(inno, randomNodeID1, randomNodeID2, 1f, true); //create gene which is enabled and 1 as default weight
  637.  
  638. InsertNewGene(gene); //add gene to the gene list
  639.  
  640. found = true; //connection made
  641. }
  642. else if(nodeList[randomNodeID1].GetNodeType() > 1 && !ConnectionExists(randomNodeID2, randomNodeID1)) { //if random node 1 isn't input type and connection does not exist with random node 2 as in node and random node 1 and out node
  643. inno = consultor.CheckGeneExistance(randomNodeID2, randomNodeID1); //get the new innovation number
  644. NEATGene gene = new NEATGene(inno, randomNodeID2, randomNodeID1, 1f, true); //create gene which is enabled and 1 as default weight
  645.  
  646. InsertNewGene(gene); //add gene to the gene list
  647.  
  648. found = true; //connection made
  649. }
  650.  
  651. if(randomNodeID1 == randomNodeID2) //both random nodes are equal
  652. totalAttemptsAllowed --; //only one attemp removed becuase only 1 connection can be made
  653. else //both nodes are different
  654. totalAttemptsAllowed -= 2; //two connections can be made
  655. }
  656.  
  657. if (found == false) { //if not found and attempts ran out
  658. AddNode(); //
  659. }
  660. }
  661.  
  662. /// <summary>
  663. /// Adding a new node between an already existing connection.
  664. /// Disable the existing connection, add a node which with connection that bbecomes the out node to the old connections in node, and a connection with in node to the old connection out node.
  665. /// The first new connections gets a weight of 1.
  666. /// The second second new connections gets a weight of the old weight
  667. /// </summary>
  668. private void AddNode(){
  669. int firstID, secondID, thirdID, inno; //first ID is old connections in node, third ID is old connections out node, second ID is the new node, and new innovation number for the connections
  670. //int randomGeneIndex = Random.Range(0, geneList.Count); //find a random gene
  671.  
  672. float oldWeight; //weight from the old gene
  673.  
  674. //NEATGene oldGene = geneList[randomGeneIndex]; //get old gene
  675.  
  676. NEATGene oldGene = null; //find a random old gene
  677. bool found = false; //used to check if old gene is found
  678.  
  679. while (!found) { //run till found
  680. int randomGeneIndex = Random.Range(0, geneList.Count); //pick random gene
  681. oldGene = geneList[randomGeneIndex]; //get gene at random index
  682. if (oldGene.GetGeneState() == true) { //if gene is active
  683. found = true; //found
  684. }
  685. }
  686.  
  687. oldGene.SetGeneState(false); //disable this gene
  688. firstID = oldGene.GetInID(); //get in node ID
  689. thirdID = oldGene.GetOutID(); //get out node ID
  690. oldWeight = oldGene.GetWeight(); //get old weight
  691.  
  692. NEATNode newNode = new NEATNode(nodeList.Count, NEATNode.HIDDEN_NODE); //create new hidden node
  693. nodeList.Add(newNode); //add new node to the node list
  694. secondID = newNode.GetNodeID(); //get new node's ID
  695.  
  696. inno = consultor.CheckGeneExistance(firstID, secondID); //get new innovation number for new gene
  697. NEATGene newGene1 = new NEATGene(inno, firstID, secondID, 1f, true); //create new gene
  698.  
  699. inno = consultor.CheckGeneExistance(secondID, thirdID); //get new innovation number for new gene
  700. NEATGene newGene2 = new NEATGene(inno, secondID, thirdID, oldWeight, true); //create new gene
  701.  
  702. //add genes to gene list
  703. InsertNewGene(newGene1);
  704. InsertNewGene(newGene2);
  705. }
  706.  
  707. /// <summary>
  708. /// Run through all genes and randomly apply various muations with a chance of 1%
  709. /// </summary>
  710. private void MutateWeight() {
  711. int numberOfGenes = geneList.Count; //number of genes
  712.  
  713. for (int i = 0; i < numberOfGenes; i++) { //run through all genes
  714. NEATGene gene = geneList[i]; // get gene at index i
  715. float weight = 0;
  716.  
  717. int randomNumber = Random.Range(1, 101); //random number between 1 and 100
  718.  
  719. if (randomNumber <= 1) { //if 1
  720. //flip sign of weight
  721. weight = gene.GetWeight();
  722. weight *= -1f;
  723. gene.SetWeight(weight);
  724. }
  725. else if (randomNumber <= 2) { //if 2
  726. //pick random weight between -1 and 1
  727. weight = Random.Range(-1f,1f);
  728. gene.SetWeight(weight);
  729. }
  730. else if (randomNumber <= 3) { //if 3
  731. //randomly increase by 0% to 100%
  732. float factor = Random.Range(0f,1f) + 1f;
  733. weight = gene.GetWeight() * factor;
  734. gene.SetWeight(weight);
  735. }
  736. else if (randomNumber <= 4) { //if 4
  737. //randomly decrease by 0% to 100%
  738. float factor = Random.Range(0f, 1f);
  739. weight = gene.GetWeight() * factor;
  740. gene.SetWeight(weight);
  741. }
  742. else if (randomNumber <= 5) { //if 5
  743. //flip activation state for gene
  744. //gene.SetGeneState(!gene.GetGeneState());
  745. }
  746. }
  747.  
  748. }
  749.  
  750. /// <summary>
  751. /// Check if a connection exists in this gene list
  752. /// </summary>
  753. /// <param name="inID">In node in gene</param>
  754. /// <param name="outID">Out node in gene</param>
  755. /// <returns>True or false if connection exists in gene list</returns>
  756. private bool ConnectionExists(int inID, int outID) {
  757. int numberOfGenes = geneList.Count; //number of genes
  758.  
  759. for (int i = 0; i < numberOfGenes; i++) { //run through gene list
  760. int nodeInID = geneList[i].GetInID(); //get in node
  761. int nodeOutID = geneList[i].GetOutID(); //get out node
  762.  
  763. if (nodeInID == inID && nodeOutID == outID) { //check if nodes match given parameters
  764. return true; //return true
  765. }
  766. }
  767.  
  768. return false; //return false if no match
  769. }
  770.  
  771. /// <summary>
  772. /// Set all node values to 0
  773. /// </summary>
  774. public void ClearNodeValues() {
  775. int numberOfNodes = nodeList.Count; //number of nodes
  776.  
  777. for (int i = 0; i < numberOfNodes; i++) { //run through all nodes
  778. nodeList[i].SetValue(0f); //set values to 0
  779. }
  780. }
  781.  
  782. /// <summary>
  783. /// Insert new gene into its proper location the gene list.
  784. /// All genes are orders in asending order based on their innovation number.
  785. /// </summary>
  786. /// <param name="gene">Gene to inset into the gene list</param>
  787. private void InsertNewGene(NEATGene gene) {
  788. int inno = gene.GetInnovation(); //get innovation number
  789. int insertIndex = FindInnovationInsertIndex(inno); //get insert index
  790.  
  791. if (insertIndex == geneList.Count) { //if insert index is equal to the size of the genome
  792. geneList.Add(gene); //add gene
  793. }
  794. else { //otherwise
  795. geneList.Insert(insertIndex, gene); //add gene to the given insert index location
  796. }
  797. }
  798.  
  799. /// <summary>
  800. /// Find the correct location to insert a given innovation number.
  801. /// Using bianry search to find insert location.
  802. /// </summary>
  803. /// <param name="inno">Innovation to insert</param>
  804. /// <returns>Location to insert the innovation number</returns>
  805. private int FindInnovationInsertIndex(int inno) {
  806. int numberOfGenes = geneList.Count; //number of genes
  807. int startIndex = 0; //start index
  808. int endIndex = numberOfGenes - 1; //end index
  809.  
  810. if (numberOfGenes == 0) { //if there are no genes
  811. return 0; //first location to insert
  812. }
  813. else if (numberOfGenes == 1) { //if there is only 1 gene
  814. if (inno > geneList[0].GetInnovation()) { //if innovation is greater than the girst gene's innovation
  815. return 1; //insert into second location
  816. }
  817. else {
  818. return 0; //insert into first location
  819. }
  820. }
  821.  
  822. while (true) { //run till found
  823. int middleIndex = (endIndex + startIndex)/2; //find middle index (middle of start and end)
  824. int middleInno = geneList[middleIndex].GetInnovation(); //get middle index's innovation number
  825.  
  826. if(endIndex-startIndex == 1) { //if there is only 1 index between start and end index (base case on recursion)
  827. int endInno = geneList[endIndex].GetInnovation(); //get end inde's innovation
  828. int startInno = geneList[startIndex].GetInnovation(); //get start index's innovation
  829.  
  830. if (inno < startInno) { //innovation is less than start innovation
  831. return startIndex; //return start index
  832. }
  833. else if (inno > endInno) { //innovation is greater than end innovation
  834. return endIndex + 1; //return end index + 1
  835. }
  836. else {
  837. return endIndex; //otherwise right in end index
  838. }
  839. }
  840. else if (inno > middleInno) { //innovation is greater than middle innovation
  841. startIndex = middleIndex; //new start index will be the middle
  842. }
  843. else { //innovation is less than middle innovation
  844. endIndex = middleIndex; //new end index is middle index
  845. }
  846. }
  847. }
  848.  
  849. /// <summary>
  850. /// Create a mutated deep copy of a given neural network
  851. /// </summary>
  852. /// <param name="net">Neural network copy to mutate</param>
  853. /// <returns>Mutated deep copy of the given neural network</returns>
  854. internal static NEATNet CreateMutateCopy(NEATNet net) {
  855. NEATNet copy = new NEATNet(net); //create deep copy of net
  856. copy.Mutate(); //mutate copy
  857. copy.GenerateNeuralNetworkFromGenome(); //< NEW LSES ADDITION
  858.  
  859. return copy; //return mutated deep copy
  860. }
  861.  
  862. /// <summary>
  863. /// Corssover between two parents neural networks to create a child neural network.
  864. /// Crossover method is as described by the NEAT algorithm.
  865. /// </summary>
  866. /// <param name="parent1">Neural network parent</param>
  867. /// <param name="parent2">Neural network parent</param>
  868. /// <returns>Child neural network</returns>
  869. internal static NEATNet Corssover (NEATNet parent1, NEATNet parent2) {
  870. NEATNet child = null; //child to create
  871.  
  872. Hashtable geneHash = new Hashtable(); //hash table to be used to compared genes from the two parents
  873.  
  874. List<NEATGene> childGeneList = new List<NEATGene>(); //new gene child gene list to be created
  875. List<NEATNode> childNodeList = null; //new child node list to be created
  876.  
  877. List<NEATGene> geneList1 = parent1.geneList; //get gene list of the parent 1
  878. List<NEATGene> geneList2 = parent2.geneList; //get gene list of parent 2
  879.  
  880. NEATConsultor consultor = parent1.GetConsultor(); //get consultor (consultor is the same for all neural network as it's just a pointer location)
  881.  
  882. int numberOfGenes1 = geneList1.Count; //get number of genes in parent 1
  883. int numberOfGenes2 = geneList2.Count; //get number of genes in parent 2
  884. int numberOfInputs = parent1.GetNumberOfInputNodes(); //number of inputs (same for both parents)
  885. int numberOfOutputs = parent1.GetNumberOfOutputNodes(); //number of outputs (same for both parents)
  886.  
  887. if (parent1.GetNodeCount() > parent2.GetNodeCount()) { //if parents 1 has more nodes than parent 2
  888. childNodeList = parent1.nodeList; //copy parent 1's node list
  889. }
  890. else { //otherwise parent 2 has euqal and more nodes than parent 1
  891. childNodeList = parent2.nodeList; //copy parent 2's node list
  892. }
  893.  
  894. for (int i = 0; i < numberOfGenes1; i++) { //run through all genes in parent 1
  895. geneHash.Add(geneList1[i].GetInnovation(),new NEATGene[] { geneList1[i], null}); //add into the hash with innovation number as the key and gene array of size 2 as value
  896. }
  897.  
  898. for (int i = 0; i < numberOfGenes2; i++) { //run through all genes in parent 2
  899. int innovationNumber = geneList2[i].GetInnovation(); //get innovation number
  900.  
  901. if (geneHash.ContainsKey(innovationNumber) == true) { //if there is a key in the hash with the given innovation number
  902. NEATGene[] geneValue = (NEATGene[])geneHash[innovationNumber]; //get gene array value with the innovation key
  903. geneValue[1] = geneList2[i]; //since this array already contains value in first location, we can add the new gene in the second location
  904. geneHash.Remove(innovationNumber); //remove old value with the key
  905. geneHash.Add(innovationNumber, geneValue); //add new value with the key
  906. }
  907. else { //there exists no key with the given innovation number
  908. geneHash.Add(innovationNumber, new NEATGene[] { null , geneList2[i] }); //add into the hash with innovation number as the key and gene array of size 2 as value
  909. }
  910. }
  911.  
  912. ICollection keysCol = geneHash.Keys; //get all keys in the hash
  913.  
  914. NEATGene gene = null; //
  915.  
  916. int[] keys = new int[keysCol.Count]; //int array with size of nuumber of keys in the hash
  917.  
  918. keysCol.CopyTo(keys,0); //copy Icollentions keys list to keys array
  919. keys = keys.OrderBy(i => i).ToArray(); //order keys in asending order
  920.  
  921. for (int i = 0; i < keys.Length; i++) { //run through all keys
  922. NEATGene[] geneValue = (NEATGene[])geneHash[keys[i]]; //get value at each index
  923.  
  924. //compare value is used to compare gene activation states in each parent
  925. int compareValue = -1;
  926. //0 = both genes are true, 1 = both are false, 2 = one is false other is true
  927. //3 = gene is dominant in one of the parents and is true, 4 = gene is dominant in one of the parents and is false
  928.  
  929. if (geneValue[0] != null && geneValue[1] != null) { //gene eixts in both parents
  930. int randomIndex = Random.Range(0, 2);
  931.  
  932. if (geneValue[0].GetGeneState() == true && geneValue[1].GetGeneState() == true) { //gene is true in both
  933. compareValue = 0; //set compared value to 0
  934. }
  935. else if (geneValue[0].GetGeneState() == false && geneValue[1].GetGeneState() == false) { //gene is false in both
  936. compareValue = 1; //set compared value to 1
  937. }
  938. else { //gene is true in one and false in the other
  939. compareValue = 2; //set compared value to 2
  940. }
  941.  
  942. gene = CrossoverCopyGene(geneValue[randomIndex], compareValue); //randomly pick a gene from eaither parent and create deep copy
  943. childGeneList.Add(gene); //add gene to the child gene list
  944. }
  945. else if (parent1.GetNetFitness() > parent2.GetNetFitness()) { //parent 1's fitness is greater than parent 2
  946. if (geneValue[0] != null) { //gene value at first index from parent 1 exists
  947. if (geneValue[0].GetGeneState() == true) { //gene is active
  948. compareValue = 3; //set compared value to 3
  949. }
  950. else { //gene is not active
  951. compareValue = 4; //set compared value to 4
  952. }
  953.  
  954. gene = CrossoverCopyGene(geneValue[0], compareValue); //deep copy parent 1's gene
  955. childGeneList.Add(gene); //add gene to the child gene list
  956. }
  957. }
  958. else if (parent1.GetNetFitness() < parent2.GetNetFitness()) { //parent 2's fitness is greater than parent 1
  959. if (geneValue[1] != null) { //gene value at second index from parent 2 exists
  960. if (geneValue[1].GetGeneState() == true) { //gene is active
  961. compareValue = 3; //set compared value to 3
  962. }
  963. else { //gene is not active
  964. compareValue = 4; //set compared value to 4
  965. }
  966.  
  967. gene = CrossoverCopyGene(geneValue[1], compareValue); //deep copy parent 2's gene
  968. childGeneList.Add(gene); //add gene to the child gene list
  969. }
  970. }
  971. else if (geneValue[0] != null) { //both parents have equal fitness and gene value at first index from parent 1 exists
  972. if (geneValue[0].GetGeneState() == true){ //gene is active
  973. compareValue = 3; //set compared value to 3
  974. }
  975. else { //gene is not active
  976. compareValue = 4; //set compared value to 4
  977. }
  978.  
  979. gene = CrossoverCopyGene(geneValue[0], compareValue); //deep copy parent 1's gene
  980. childGeneList.Add(gene); //add gene to the child gene list
  981. }
  982. else if (geneValue[1] != null) { //both parents have equal fitness and gene value at second index from parent 2 exists
  983. if (geneValue[1].GetGeneState() == true) { //gene is active
  984. compareValue = 3; //set compared value to 3
  985. }
  986. else { //gene is not active
  987. compareValue = 4; //set compared value to 4
  988. }
  989.  
  990. gene = CrossoverCopyGene(geneValue[1], compareValue); //deep copy parent 2's gene
  991. childGeneList.Add(gene); //add gene to the child gene list
  992. }
  993. }
  994.  
  995. child = new NEATNet(consultor, numberOfInputs, numberOfOutputs, childNodeList, childGeneList); //create new child neural network
  996. return child; //return newly created neural network
  997. }
  998.  
  999. /// <summary>
  1000. /// Created a deep copy of a given gene.
  1001. /// This gene can be muated with a small chance based on the compare value.
  1002. /// Deactivated genes have a small chance of being activated based on the compare value.
  1003. /// </summary>
  1004. /// <param name="copyGene">Gene to deep copy</param>
  1005. /// <param name="compareValue">Value to use when activating a gene</param>
  1006. /// <returns>Deep copied gene</returns>
  1007. private static NEATGene CrossoverCopyGene(NEATGene copyGene, int compareValue) {
  1008. NEATGene gene = new NEATGene(copyGene); //deep copy gene
  1009.  
  1010. /*int randomNumber = Random.Range(0, 20); //0-19
  1011. if (compareValue == 2) { //if gene is false in both parents
  1012. randomNumber = Random.Range(0, 10); //0-9
  1013. if (randomNumber == 0) { //10% chance of activating this gene
  1014. gene.SetGeneState(true); //activate
  1015. }
  1016. }
  1017. else if (gene.GetGeneState() == false && randomNumber == 0) { //gene is false and 20% chance of activating this gene
  1018. gene.SetGeneState(true); //activate
  1019. }*/
  1020.  
  1021. int factor = 2;
  1022. if (compareValue == 1) {
  1023. int randomNumber = Random.Range(0, 25* factor);
  1024. if (randomNumber == 0) {
  1025. gene.SetGeneState(false);
  1026. }
  1027. }
  1028. else if (compareValue == 2) {
  1029. int randomNumber = Random.Range(0, 10 * factor);
  1030. if (randomNumber == 0) {
  1031. gene.SetGeneState(true);
  1032. }
  1033. }
  1034. else {
  1035. int randomNumber = Random.Range(0, 25 * factor);
  1036. if (randomNumber == 0) {
  1037. gene.SetGeneState(!gene.GetGeneState());
  1038. }
  1039. }
  1040.  
  1041. return gene; //return new gene
  1042. }
  1043.  
  1044. /// <summary>
  1045. /// Check whether two neural networks belong to the same species based on defined coefficient values in the consultor
  1046. /// </summary>
  1047. /// <param name="net1">Neural network to compare</param>
  1048. /// <param name="net2">Neural network to compare</param>
  1049. /// <returns>True of false whether they belong to the same species</returns>
  1050. internal static bool SameSpeciesV2(NEATNet net1, NEATNet net2) {
  1051. Hashtable geneHash = new Hashtable(); //hash table to be used to compared genes from the two networks
  1052. NEATConsultor consultor = net1.consultor; //get consultor (consultor is the same for all neural network as it's just a pointer location)
  1053. NEATGene[] geneValue; //will be used to check whether a gene exists in both networks
  1054.  
  1055. List<NEATGene> geneList1 = net1.geneList; //get first network
  1056. List<NEATGene> geneList2 = net2.geneList; //get second network
  1057.  
  1058. ICollection keysCol; //will be used to get keys from gene hash
  1059. int[] keys; //will be used to get keys arrray from ICollections
  1060.  
  1061. int numberOfGenes1 = geneList1.Count; //get number of genes in network 1
  1062. int numberOfGenes2 = geneList2.Count; //get number of genes in network 2
  1063. int largerGenomeSize = numberOfGenes1 > numberOfGenes2 ? numberOfGenes1 : numberOfGenes2; //get one that is larger between the 2 network
  1064. int excessGenes = 0; //number of excess genes (genes that do match and are outside the innovation number of the other network)
  1065. int disjointGenes = 0; //number of disjoint gene (genes that do not match in the two networks)
  1066. int equalGenes = 0; //number of genes both neural network have
  1067.  
  1068. float disjointCoefficient = consultor.GetDisjointCoefficient(); //get disjoint coefficient from consultor
  1069. float excessCoefficient = consultor.GetExcessCoefficient(); //get excess coefficient from consultor
  1070. float averageWeightDifferenceCoefficient = consultor.GetAverageWeightDifferenceCoefficient(); //get average weight difference coefficient
  1071. float deltaThreshold = consultor.GetDeltaThreshold(); //get threshold
  1072. float similarity = 0; //similarity of the two networks
  1073. float averageWeightDifference = 0; //average weight difference of the two network's equal genes
  1074.  
  1075. bool foundAllExcess = false; //if all excess genes are found
  1076. bool isFirstGeneExcess = false; //if net 1 contains the excess genes
  1077.  
  1078. for (int i = 0; i < geneList1.Count; i++) { //run through net 1's genes
  1079. int innovation = geneList1[i].GetInnovation(); //get innovation number of gene
  1080.  
  1081. geneValue = new NEATGene[] {geneList1[i], null}; //add into the hash with innovation number as the key and gene array of size 2 as value
  1082. geneHash.Add(innovation, geneValue); //add into the hash with innovation number as the key and gene array of size 2 as value
  1083. }
  1084.  
  1085. for (int i = 0; i < geneList2.Count; i++) { //run through net 2's genes
  1086. int innovation = geneList2[i].GetInnovation(); //get innovation number of gene
  1087.  
  1088. if (!geneHash.ContainsKey(innovation)) { //if innovation key does not exist
  1089. geneValue = new NEATGene[] {null, geneList2[i]}; //create array of size 2 with new gene in the second position
  1090. geneHash.Add(innovation, geneValue); //add into the hash with innovation number as the key and gene array of size 2 as value
  1091. }
  1092. else { //key exists
  1093. geneValue = (NEATGene[]) geneHash[innovation]; //get value
  1094. geneValue[1] = geneList2[i]; //add into second position net 2's gene
  1095. }
  1096. }
  1097.  
  1098. keysCol = geneHash.Keys; //get all keys from gene hash
  1099. keys = new int[keysCol.Count]; //create array with size of number of keys
  1100. keysCol.CopyTo(keys, 0); //copy all keys from ICollections to array
  1101. keys = keys.OrderBy(i => i).ToArray(); //order keys in ascending order
  1102.  
  1103. for (int i = keys.Length-1; i >= 0; i--) { //run through all keys backwards (to get all excess gene's first)
  1104. geneValue = (NEATGene[])geneHash[keys[i]]; //get value with key
  1105.  
  1106. if (foundAllExcess == false) { //if all excess genes have not been found
  1107. if (i == keys.Length - 1 && geneValue[1] == null) { //this is the first itteration and second gene location is null
  1108. isFirstGeneExcess = true; //excess genes exit in net 1
  1109. }
  1110.  
  1111. if (isFirstGeneExcess == true && geneValue[1] == null) { //excess gene exist in net 1 and there is no gene in second location of the value
  1112. excessGenes++; //this is an excess gene and increment excess gene
  1113. }
  1114. else if (isFirstGeneExcess == false && geneValue[0] == null) { //excess gene exist in net 12 and there is no gene in first location of the value
  1115. excessGenes++; //this is an excess gene and increment excess gene
  1116. }
  1117. else { //no excess genes
  1118. foundAllExcess = true; //all excess genes are found
  1119. }
  1120.  
  1121. }
  1122.  
  1123. if(foundAllExcess == true){ //if all excess genes are found
  1124. if (geneValue[0] != null && geneValue[1] != null) { //both gene location are not null
  1125. equalGenes++; //increment equal genes
  1126. averageWeightDifference += Mathf.Abs(geneValue[0].GetWeight() - geneValue[1].GetWeight()); //add absolute difference between 2 weight
  1127. }
  1128. else { //this is disjoint gene
  1129. disjointGenes++; //increment disjoint
  1130. }
  1131. }
  1132. }
  1133.  
  1134. averageWeightDifference = averageWeightDifference / (float)equalGenes; //get average weight difference of equal genes
  1135.  
  1136. //similarity formula -> Sim = (AVG_DIFF * AVG_COFF) + (((DISJ*DISJ_COFF) + (EXSS*EXSS_COFF)) /GENOME_SIZE)
  1137. similarity = (averageWeightDifference * averageWeightDifferenceCoefficient) + //calculate weight difference disparity
  1138. (((float)disjointGenes * disjointCoefficient) / (float)largerGenomeSize) + //calculate disjoint disparity
  1139. (((float)excessGenes * excessCoefficient) / (float)largerGenomeSize); //calculate excess disparity
  1140.  
  1141. //if similairty is <= to threshold then return true, otherwise false
  1142. return similarity<=deltaThreshold; //return boolean compare value
  1143. }
  1144.  
  1145. /// <summary>
  1146. /// ---ONLY USED FOR DEBUGGING---
  1147. /// Prints all neural network details.
  1148. /// </summary>
  1149. public void PrintDetails() {
  1150. int numberOfNodes = nodeList.Count; //get number of nodes
  1151. int numberOfGenes = geneList.Count; //get number of genes
  1152.  
  1153. //Print various node details to Unity Log
  1154. Debug.Log("-----------------");
  1155.  
  1156. for (int i = 0; i < numberOfNodes; i++) {
  1157. NEATNode node = nodeList[i];
  1158. Debug.Log("ID:" + node.GetNodeID() + ", Type:" + node.GetNodeType());
  1159. }
  1160.  
  1161. Debug.Log("-----------------");
  1162.  
  1163. for (int i = 0; i < numberOfGenes; i++) {
  1164. NEATGene gene = geneList[i];
  1165. Debug.LogWarning("Inno " + gene.GetInnovation() + ", In:" + gene.GetInID() + ", Out:" + gene.GetOutID() + ", On:" + gene.GetGeneState() + ", Wi:" + gene.GetWeight());
  1166. }
  1167.  
  1168. Debug.Log("-----------------");
  1169. }
  1170.  
  1171. }
Advertisement
Add Comment
Please, Sign In to add comment