Advertisement
Guest User

NEATBrain.cs

a guest
Jan 8th, 2017
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 30.11 KB | None | 0 0
  1. 860 lines (725 sloc) 29.7 KB
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. using System;
  5. using System.Collections;
  6. using System.Linq;
  7.  
  8.  
  9. //Fast neural network based on matrix operations
  10. public class NEATBrain : IEquatable<NEATBrain>
  11. {
  12. private string name;
  13. private int ID;
  14. private int calculations;
  15. private int numberOfInputNeurons;
  16. private int numberOfOutputNeurons;
  17. private int numberOfHiddenNeurons;
  18.  
  19. private int usedHiddenNeuronIndex;
  20. private List<Gene> genome = new List<Gene>();
  21. private HashSet<int> genomeHash;
  22.  
  23. private List<Neuron> network = new List<Neuron>();
  24. private Neuron[] networkArray;
  25. private NEATConsultor consultor;
  26.  
  27. private BehaviourGenome behaviourGenome;
  28.  
  29. public NEATBrain(int numberOfInputNeurons, int numberOfOutputNeurons, int numberOfHiddenNeurons, int ID)
  30. {
  31. consultor = NEATConsultor.GetInstance();
  32. this.ID = ID;
  33. this.numberOfHiddenNeurons = numberOfHiddenNeurons;
  34. this.numberOfInputNeurons = numberOfInputNeurons;
  35. this.numberOfOutputNeurons = numberOfOutputNeurons;
  36. this.numberOfInputNeurons++; //bias
  37.  
  38. this.usedHiddenNeuronIndex = this.numberOfOutputNeurons + this.numberOfInputNeurons;
  39.  
  40. //InitilizeGenome();
  41. GenerateRandomName();
  42.  
  43. genomeHash = new HashSet<int>();
  44.  
  45. InitilizeNeurons();
  46. for (int i = 0; i < 2; i++)
  47. Mutate();
  48.  
  49. MakeNetwork();
  50.  
  51. behaviourGenome = new BehaviourGenome();
  52. }
  53.  
  54. public NEATBrain(NEATBrain copy, Neuron[] neuronArray)
  55. {
  56. consultor = NEATConsultor.GetInstance();
  57. this.numberOfHiddenNeurons = copy.numberOfHiddenNeurons;
  58. this.numberOfInputNeurons = copy.numberOfInputNeurons;
  59. this.numberOfOutputNeurons = copy.numberOfOutputNeurons;
  60. this.usedHiddenNeuronIndex = copy.usedHiddenNeuronIndex;
  61.  
  62. this.networkArray = neuronArray;
  63. }
  64.  
  65. // Deep copy constructor of a given Brain
  66. public NEATBrain(NEATBrain parentBrain, int ID)
  67. {
  68. consultor = NEATConsultor.GetInstance();
  69. this.ID = ID;
  70. this.calculations = parentBrain.calculations;
  71. this.name = parentBrain.name;
  72. this.numberOfHiddenNeurons = parentBrain.numberOfHiddenNeurons;
  73. this.numberOfInputNeurons = parentBrain.numberOfInputNeurons;
  74. this.numberOfOutputNeurons = parentBrain.numberOfOutputNeurons;
  75. this.usedHiddenNeuronIndex = parentBrain.usedHiddenNeuronIndex;
  76.  
  77. InitilizeGenomeFromParent(parentBrain.genome);
  78. InitilizeNeurons();
  79. Mutate();
  80. MakeNetwork();
  81.  
  82. behaviourGenome = new BehaviourGenome(parentBrain.behaviourGenome);
  83. }
  84.  
  85. public void InitilizeNeurons()
  86. {
  87. for (int i = 0; i < numberOfInputNeurons + numberOfOutputNeurons; i++)
  88. {
  89. Neuron neuron = new Neuron(i, 0f);
  90. network.Add(neuron);
  91. }
  92. }
  93.  
  94. private void MakeNetwork()
  95. {
  96. calculations = 0;
  97. genome.Sort((x, y) => x.outNode.CompareTo(y.outNode));
  98. HashSet<int> tempNeuronHash = new HashSet<int>();
  99.  
  100. for (int i = 0; i < numberOfInputNeurons + numberOfOutputNeurons; i++)
  101. {
  102. tempNeuronHash.Add(i);
  103. }
  104.  
  105. for (int i = 0; i < genome.Count; i++)
  106. {
  107. Gene gene = genome[i];
  108. if (!tempNeuronHash.Contains(gene.inNode))
  109. {
  110. Neuron neuron = new Neuron(gene.inNode,0f);
  111. tempNeuronHash.Add(gene.inNode);
  112. network.Add(neuron);
  113. }
  114.  
  115. if (!tempNeuronHash.Contains(gene.outNode))
  116. {
  117. Neuron neuron = new Neuron(gene.outNode,0f);
  118. tempNeuronHash.Add(gene.outNode);
  119. network.Add(neuron);
  120. }
  121. }
  122.  
  123. network.Sort((x, y) => x.id.CompareTo(y.id));
  124.  
  125. for (int i = 0; i < genome.Count; i++)
  126. {
  127. Gene gene = genome[i];
  128.  
  129. if (gene.active == true)
  130. {
  131. network[gene.outNode].incomming.Add(gene);
  132. calculations++;
  133. }
  134. }
  135.  
  136. networkArray = network.ToArray();
  137. for (int i = 0; i < networkArray.Length; i++)
  138. {
  139. networkArray[i].incomming.Sort((x, y) => x.inNode.CompareTo(y.inNode));
  140. networkArray[i].incommingArray = networkArray[i].incomming.ToArray();
  141. }
  142. }
  143.  
  144. /*private void InitilizeGenome()
  145. {
  146. genomeHash = new HashSet<int>();
  147. for (int i = 0; i < numberOfInputNeurons; i++)
  148. {
  149. for (int j = numberOfInputNeurons; j < numberOfInputNeurons + numberOfOutputNeurons; j++)
  150. {
  151. AddGene(i, j, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  152. }
  153. }
  154. }*/
  155.  
  156. private void InitilizeGenomeFromParent(List<Gene> parentGenome)
  157. {
  158. genomeHash = new HashSet<int>();
  159.  
  160. for (int i = 0; i < parentGenome.Count; i++)
  161. {
  162. Gene gene = parentGenome[i];
  163. AddGene(gene.inno, gene.inNode, gene.outNode, gene.weight, gene.active);
  164. }
  165. }
  166.  
  167. public List<Gene> GetGenome()
  168. {
  169. return genome;
  170. }
  171.  
  172. public int GetUsedHiddenNeuronCount()
  173. {
  174. return usedHiddenNeuronIndex;
  175. }
  176.  
  177. private int GetGeneHashValue(int inNode, int outNode)
  178. {
  179. return ((GetIntegerHashMultiplyFactor(inNode + 1, outNode + 1) * (inNode + 1)) + (outNode + 1));
  180. }
  181.  
  182. private int GetIntegerHashMultiplyFactor(int int1, int int2)
  183. {
  184. int integer = int1 > int2 ? int1 : int2;
  185.  
  186. if (integer >= 100)
  187. return 1000;
  188. else if (integer >= 10)
  189. return 100;
  190. else
  191. return 10;
  192. }
  193.  
  194. private void AddGene(int inNode, int outNode, float weight, bool active)
  195. {
  196. int inno = consultor.GetInnovationNumber(inNode,outNode);
  197. //Debug.Log(inno+" "+ inNode+" "+outNode);
  198. Gene gene = new Gene(inno, inNode, outNode, weight, active);
  199. genome.Add(gene);
  200. int geneHashValue = GetGeneHashValue(inNode, outNode);
  201. genomeHash.Add(geneHashValue);
  202. }
  203.  
  204. private void AddGene(int inno, int inNode, int outNode, float weight, bool active)
  205. {
  206. Gene gene = new Gene(inno, inNode, outNode, weight, active);
  207. genome.Add(gene);
  208. int geneHashValue = GetGeneHashValue(inNode, outNode);
  209. genomeHash.Add(geneHashValue);
  210. }
  211.  
  212. public void RemoveGene(int index)
  213. {
  214. int geneHashValue = GetGeneHashValue(genome[index].inNode, genome[index].outNode);
  215. genome.RemoveAt(index);
  216. genomeHash.Remove(geneHashValue);
  217. }
  218.  
  219. //hyperbolic tangent activation
  220. private float Tanh(float value)
  221. {
  222. return (float)Math.Tanh(value);
  223. }
  224.  
  225. //random name generation, with atlest 1 vowel per 3 letters
  226. private void GenerateRandomName()
  227. {
  228. int nameSize = UnityEngine.Random.Range(3, 11);
  229. char[] name = new char[nameSize];
  230.  
  231. int[] vowels = new int[] { 97, 101, 105, 111, 117 };
  232. int vowelCounter = 1;
  233. for (int i = 0; i < name.Length; i++)
  234. {
  235. int charNum = UnityEngine.Random.Range(97, 123);
  236.  
  237. bool isVowel = false;
  238. for (int j = 0; j < vowels.Length; j++)
  239. {
  240. if (charNum == vowels[j])
  241. {
  242. isVowel = true;
  243. break;
  244. }
  245. }
  246.  
  247. if (isVowel)
  248. {
  249. vowelCounter = 1;
  250. }
  251. else if (vowelCounter == 3)
  252. {
  253. vowelCounter = 1;
  254. charNum = vowels[UnityEngine.Random.Range(0, vowels.Length)];
  255. }
  256.  
  257. vowelCounter++;
  258. name[i] = (char)charNum;
  259. }
  260. this.name = new string(name);
  261. }
  262.  
  263. public string GetName()
  264. {
  265. return name;
  266. }
  267.  
  268. public bool Equals(NEATBrain other)
  269. {
  270. if (other == null)
  271. return false;
  272.  
  273. return (other.ID == this.ID);
  274. }
  275.  
  276. public void SetID(int ID)
  277. {
  278. this.ID = ID;
  279. }
  280.  
  281. public int GetNumberOfInputNeurons()
  282. {
  283. return numberOfInputNeurons;
  284. }
  285.  
  286. public int GetNumberOfUsedHiddenNeurons()
  287. {
  288. return usedHiddenNeuronIndex-(numberOfInputNeurons+numberOfOutputNeurons);
  289. }
  290.  
  291. public int GetNumberOfOutputNeurons()
  292. {
  293. return numberOfOutputNeurons;
  294. }
  295.  
  296. public Neuron[] GetNetworkArray()
  297. {
  298. return networkArray;
  299. }
  300.  
  301. public void Mutate()
  302. {
  303. bool initialConnection = false;
  304. int[] numberOfConnectedInputNeurons = new int[numberOfInputNeurons];
  305. for (int i = 0;i<genome.Count;i++)
  306. {
  307. Gene gene = genome[i];
  308. if (gene.inNode < numberOfInputNeurons && gene.active == true)
  309. {
  310. numberOfConnectedInputNeurons[gene.inNode]++;
  311. }
  312. }
  313. for (int i = 0; i < numberOfInputNeurons; i++)
  314. {
  315. if (numberOfConnectedInputNeurons[i] == 0)
  316. {
  317. int inNode = i;
  318. int randomOutNode = UnityEngine.Random.Range(numberOfInputNeurons, usedHiddenNeuronIndex);
  319. bool ret1 = CheckIfGeneExists(inNode, randomOutNode);
  320. if (ret1 == false) //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  321. {
  322. AddGene(inNode, randomOutNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  323. }
  324. initialConnection = true;
  325. }
  326. }
  327.  
  328. if (initialConnection == false)
  329. {
  330. if (genome.Count > 0)
  331. {
  332. float randomMutateType = UnityEngine.Random.Range(1f, 100f);
  333.  
  334. if (randomMutateType <= 1f)
  335. {
  336. if (genome.Count >= (numberOfInputNeurons * numberOfOutputNeurons))
  337. {
  338. int randomIndex = UnityEngine.Random.Range(0, genome.Count);
  339. RemoveGene(randomIndex);
  340. }
  341. }
  342. else if (randomMutateType <= 50f)
  343. {
  344. float randomMutateValue = UnityEngine.Random.Range(1f, 100f);
  345. if (randomMutateValue <=50)
  346. {
  347.  
  348. if (usedHiddenNeuronIndex < (numberOfOutputNeurons + numberOfHiddenNeurons + numberOfInputNeurons))
  349. {
  350. int randomIndex = UnityEngine.Random.Range(0, genome.Count);
  351. Gene gene = genome[randomIndex];
  352. gene.active = false;
  353.  
  354. AddGene(gene.inNode, usedHiddenNeuronIndex, /*UnityEngine.Random.Range(-0.5f, 0.5f)*/ 1f, true);
  355. AddGene(usedHiddenNeuronIndex, gene.outNode, gene.weight, true);
  356.  
  357. usedHiddenNeuronIndex++;
  358. }
  359. }
  360. else if (randomMutateValue <=100)
  361. {
  362. int randomInNode = UnityEngine.Random.Range(0, usedHiddenNeuronIndex);
  363. int randomOutNode = UnityEngine.Random.Range(numberOfInputNeurons, usedHiddenNeuronIndex);
  364. bool ret1 = CheckIfGeneExists(randomInNode, randomOutNode);
  365. bool ret2 = CheckIfGeneExists(randomOutNode, randomInNode);
  366. bool ret3 = CheckIfGeneExists(randomInNode, randomInNode);
  367. bool ret4 = CheckIfGeneExists(randomOutNode, randomOutNode);
  368.  
  369. if (ret1 == true && ret2 == false && randomInNode >= numberOfInputNeurons)
  370. {
  371. AddGene(randomOutNode, randomInNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  372. }
  373. else if (ret1 == false)
  374. {
  375. AddGene(randomInNode, randomOutNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  376. }
  377. else if (ret3 == true && randomInNode >= numberOfInputNeurons)
  378. {
  379. //AddGene(randomInNode, randomInNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  380. }
  381. else if (ret4 == false)
  382. {
  383. AddGene(randomOutNode, randomOutNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  384. }
  385. else
  386. {
  387. //int randomIndex = UnityEngine.Random.Range(0, genome.Count);
  388. //genome[randomIndex].active = !genome[randomIndex].active;
  389. //if (genome[randomIndex].active == false)
  390. //genome[randomIndex].active = true;
  391. }
  392. }
  393. }
  394. }
  395. else
  396. {
  397. int randomInNode = UnityEngine.Random.Range(0, usedHiddenNeuronIndex);
  398. int randomOutNode = UnityEngine.Random.Range(numberOfInputNeurons, usedHiddenNeuronIndex);
  399. bool ret1 = CheckIfGeneExists(randomInNode, randomOutNode);
  400. bool ret2 = CheckIfGeneExists(randomOutNode, randomInNode);
  401. bool ret3 = CheckIfGeneExists(randomInNode, randomInNode);
  402. bool ret4 = CheckIfGeneExists(randomOutNode, randomOutNode);
  403.  
  404. if (ret1 == true && ret2 == false && randomInNode >= numberOfInputNeurons)
  405. {
  406. AddGene(randomOutNode, randomInNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  407. }
  408. else if (ret1 == false)
  409. {
  410. AddGene(randomInNode, randomOutNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  411. }
  412. else if (ret3 == true && randomInNode >= numberOfInputNeurons)
  413. {
  414. //AddGene(randomInNode, randomInNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  415. }
  416. else if (ret4 == false)
  417. {
  418. AddGene(randomOutNode, randomOutNode, UnityEngine.Random.Range(-0.5f, 0.5f), true);
  419. }
  420. }
  421. }
  422.  
  423. MutateGenes();
  424. MutateName();
  425. }
  426.  
  427. private void MutateGenes()
  428. {
  429. int numberOfGenes = genome.Count; //number of genes
  430.  
  431. for (int i = 0; i < numberOfGenes; i++)
  432. { //run through all genes
  433. Gene gene = genome[i]; // get gene at index i
  434. float weight = 0;
  435.  
  436. int randomNumber = UnityEngine.Random.Range(1, 101); //random number between 1 and 100
  437.  
  438. if (randomNumber <= 1)
  439. { //if 1
  440. //flip sign of weight
  441. weight = gene.weight;
  442. weight *= -1f;
  443. gene.weight = weight;
  444. }
  445. else if (randomNumber <= 2)
  446. { //if 2
  447. //pick random weight between -1 and 1
  448. weight = UnityEngine.Random.Range(-0.5f, 0.5f);
  449. gene.weight = weight;
  450. }
  451. else if (randomNumber <= 3)
  452. { //if 3
  453. //randomly increase by 0% to 100%
  454. float factor = UnityEngine.Random.Range(0f, 1f) + 1f;
  455. weight = gene.weight * factor;
  456. gene.weight = weight;
  457. }
  458. else if (randomNumber <= 4)
  459. { //if 4
  460. //randomly decrease by 0% to 100%
  461. float factor = UnityEngine.Random.Range(0f, 1f);
  462. weight = gene.weight * factor;
  463. gene.weight = weight;
  464. }
  465. else if (randomNumber <= 5)
  466. { //if 5
  467. //flip activation state for gene
  468. //gene.active = !gene.active;
  469. }
  470. }
  471.  
  472. }
  473.  
  474. public bool CheckIfGeneExists(int inNode, int outNode)
  475. {
  476.  
  477. /*for (int i = 0; i < genome.Count; i++)
  478. {
  479. Gene gene = genome[i];
  480. if (gene.inNode == inNode && gene.outNode == outNode)
  481. {
  482. return 1;
  483. }
  484. }*/
  485.  
  486. return genomeHash.Contains(GetGeneHashValue(inNode, outNode));
  487. }
  488.  
  489. public int GetCalculations()
  490. {
  491. return calculations;
  492. }
  493.  
  494. private void MutateName()
  495. {
  496. //Mutate name
  497. int index = UnityEngine.Random.Range(0, name.Length);
  498. char[] nameChar = name.ToCharArray();
  499. List<char> nameCharList = new List<char>(nameChar);
  500.  
  501. int randomNumber = UnityEngine.Random.Range(0, 3);
  502. if (randomNumber == 0)
  503. {
  504. nameChar[index] = (char)UnityEngine.Random.Range(97, 123);
  505. name = new string(nameChar);
  506. }
  507. else if (randomNumber == 1)
  508. {
  509. if (nameCharList.Count >= 4)
  510. {
  511. nameCharList.RemoveAt(UnityEngine.Random.Range(0, nameCharList.Count));
  512.  
  513. }
  514. else
  515. {
  516. nameCharList.Add((char)UnityEngine.Random.Range(97, 123));
  517. }
  518.  
  519. nameChar = nameCharList.ToArray();
  520. name = new string(nameChar);
  521. }
  522. else if (randomNumber == 2)
  523. {
  524.  
  525. if (nameCharList.Count < 10)
  526. {
  527. int locationToAdd = UnityEngine.Random.Range(0, nameCharList.Count);
  528. nameCharList.Insert(locationToAdd, (char)UnityEngine.Random.Range(97, 123));
  529. }
  530. else
  531. {
  532. nameCharList.RemoveAt(UnityEngine.Random.Range(0, nameCharList.Count));
  533. }
  534.  
  535. nameChar = nameCharList.ToArray();
  536. name = new string(nameChar);
  537.  
  538. }
  539. }
  540.  
  541. public float[] GetOutput()
  542. {
  543. /*float[] output = new float[numberOfOutputNeurons];
  544. for (int i = 0; i < output.Length; i++)
  545. {
  546. output[i] = nodes[numberOfInputNeurons + i];
  547. }
  548. return output;*/
  549.  
  550. float[] output = new float[numberOfOutputNeurons];
  551. for (int i = 0; i < output.Length; i++)
  552. {
  553. output[i] = network[i + numberOfInputNeurons].value;
  554.  
  555. }
  556.  
  557. return output;
  558. }
  559.  
  560. public float Sigmoid(float value)
  561. {
  562. return 2f / (1f + (float)Math.Exp(-2f * value)) - 1f;
  563. }
  564.  
  565. private float activation(float value, int type)
  566. {
  567. switch (type)
  568. {
  569. case 0: return Tanh(value);
  570. case 1: return Mathf.Sin(value);
  571. case 2: return Sigmoid(value);
  572. default: return Tanh(value);
  573. }
  574. }
  575.  
  576. public float[] FeedForward(float[] inputs)
  577. {
  578. for (int i = 0; i < inputs.Length; i++)
  579. {
  580. networkArray[i].value = inputs[i];
  581.  
  582. }
  583.  
  584. float[] output = new float[numberOfOutputNeurons];
  585.  
  586. float[] tempValues = new float[networkArray.Length];
  587. for (int i = 0; i < tempValues.Length;i++)
  588. tempValues[i] = networkArray[i].value;
  589.  
  590. networkArray[numberOfInputNeurons - 1].value = 1f;
  591.  
  592. for (int i = 0; i < networkArray.Length; i++)
  593. {
  594. float value = 0;
  595. Neuron neuron = networkArray[i];
  596. Gene[] incommingArray = neuron.incommingArray;
  597.  
  598. if (incommingArray.Length > 0)
  599. {
  600. for (int j = 0; j < incommingArray.Length; j++)
  601. {
  602. if (incommingArray[j].active == true)
  603. {
  604. value = value + (incommingArray[j].weight * /*network[incomming[j].inNode].value*/ tempValues[incommingArray[j].inNode]);
  605. }
  606. }
  607. neuron.value = Tanh(value);
  608. }
  609. }
  610.  
  611. return GetOutput();
  612. }
  613.  
  614. internal static float BrainSimilarityScore(NEATBrain net1, NEATBrain net2)
  615. {
  616. //Debug.Log("___________________________________________");
  617. Hashtable geneHash = new Hashtable(); //hash table to be used to compared genes from the two networks
  618. Gene[] geneValue; //will be used to check whether a gene exists in both networks
  619.  
  620. List<Gene> geneList1 = net1.genome; //get first network
  621. List<Gene> geneList2 = net2.genome; //get second network
  622.  
  623. ICollection keysCol; //will be used to get keys from gene hash
  624. int[] keys; //will be used to get keys arrray from ICollections
  625.  
  626. int numberOfGenes1 = geneList1.Count; //get number of genes in network 1
  627. int numberOfGenes2 = geneList2.Count; //get number of genes in network 2
  628. int largerGenomeSize = numberOfGenes1 > numberOfGenes2 ? numberOfGenes1 : numberOfGenes2; //get one that is larger between the 2 network
  629. int excessGenes = 0; //number of excess genes (genes that do match and are outside the innovation number of the other network)
  630. int disjointGenes = 0; //number of disjoint gene (genes that do not match in the two networks)
  631. int equalGenes = 0; //number of genes both neural network have
  632.  
  633. float disjointCoefficient = 0.85f; //get disjoint coefficient from consultor
  634. float excessCoefficient = 1f; //get excess coefficient from consultor
  635. float averageWeightDifferenceCoefficient = 1f; //get average weight difference coefficient
  636.  
  637. float similarity = 0; //similarity of the two networks
  638. float averageWeightDifference = 0; //average weight difference of the two network's equal genes
  639.  
  640. bool foundAllExcess = false; //if all excess genes are found
  641. bool isFirstGeneExcess = false; //if net 1 contains the excess genes
  642.  
  643. for (int i = 0; i < geneList1.Count; i++)
  644. { //run through net 1's genes
  645. int innovation = geneList1[i].inno; //get innovation number of gene
  646. //Debug.Log(innovation+" "+ geneList1[i].inNode+" "+ geneList1[i].outNode);
  647. geneValue = new Gene[] { geneList1[i], null }; //add into the hash with innovation number as the key and gene array of size 2 as value
  648.  
  649. //try {
  650. geneHash.Add(innovation, geneValue); //add into the hash with innovation number as the key and gene array of size 2 as value
  651. /*}
  652. catch (ArgumentException error)
  653. {
  654. Debug.Log(innovation+" "+ geneList1[i].inNode+" "+geneList1[i].outNode+" ERRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRROR");
  655. }*/
  656. }
  657.  
  658. for (int i = 0; i < geneList2.Count; i++)
  659. { //run through net 2's genes
  660. int innovation = geneList2[i].inno; //get innovation number of gene
  661.  
  662. if (!geneHash.ContainsKey(innovation))
  663. { //if innovation key does not exist
  664. geneValue = new Gene[] { null, geneList2[i] }; //create array of size 2 with new gene in the second position
  665. geneHash.Add(innovation, geneValue); //add into the hash with innovation number as the key and gene array of size 2 as value
  666. }
  667. else
  668. { //key exists
  669. geneValue = (Gene[])geneHash[innovation]; //get value
  670. geneValue[1] = geneList2[i]; //add into second position net 2's gene
  671. }
  672. }
  673.  
  674. keysCol = geneHash.Keys; //get all keys from gene hash
  675. keys = new int[keysCol.Count]; //create array with size of number of keys
  676. keysCol.CopyTo(keys, 0); //copy all keys from ICollections to array
  677. keys = keys.OrderBy(i => i).ToArray(); //order keys in ascending order
  678.  
  679. for (int i = keys.Length - 1; i >= 0; i--)
  680. { //run through all keys backwards (to get all excess gene's first)
  681. geneValue = (Gene[])geneHash[keys[i]]; //get value with key
  682.  
  683. if (foundAllExcess == false)
  684. { //if all excess genes have not been found
  685. if (i == keys.Length - 1 && geneValue[1] == null)
  686. { //this is the first itteration and second gene location is null
  687. isFirstGeneExcess = true; //excess genes exit in net 1
  688. }
  689.  
  690. if (isFirstGeneExcess == true && geneValue[1] == null)
  691. { //excess gene exist in net 1 and there is no gene in second location of the value
  692. excessGenes++; //this is an excess gene and increment excess gene
  693. }
  694. else if (isFirstGeneExcess == false && geneValue[0] == null)
  695. { //excess gene exist in net 12 and there is no gene in first location of the value
  696. excessGenes++; //this is an excess gene and increment excess gene
  697. }
  698. else
  699. { //no excess genes
  700. foundAllExcess = true; //all excess genes are found
  701. }
  702.  
  703. }
  704.  
  705. if (foundAllExcess == true)
  706. { //if all excess genes are found
  707. if (geneValue[0] != null && geneValue[1] != null)
  708. { //both gene location are not null
  709. equalGenes++; //increment equal genes
  710. averageWeightDifference += Mathf.Abs(geneValue[0].weight - geneValue[1].weight); //add absolute difference between 2 weight
  711. }
  712. else
  713. { //this is disjoint gene
  714. disjointGenes++; //increment disjoint
  715. }
  716. }
  717. }
  718.  
  719. averageWeightDifference = averageWeightDifference / (float)equalGenes; //get average weight difference of equal genes
  720.  
  721. //similarity formula -> Sim = (AVG_DIFF * AVG_COFF) + (((DISJ*DISJ_COFF) + (EXSS*EXSS_COFF)) /GENOME_SIZE)
  722. similarity = (averageWeightDifference * averageWeightDifferenceCoefficient) + //calculate weight difference disparity
  723. (((float)disjointGenes * disjointCoefficient) / (float)largerGenomeSize) + //calculate disjoint disparity
  724. (((float)excessGenes * excessCoefficient) / (float)largerGenomeSize); //calculate excess disparity
  725.  
  726. //if similairty is <= to threshold then return true, otherwise false
  727. return similarity; //return boolean compare value
  728.  
  729. }
  730.  
  731. internal static NEATBrain MakeDifferentialBrain(NEATBrain net1, NEATBrain net2)
  732. {
  733. NEATBrain difference = null;
  734. List<Neuron> differenceNeurons = new List<Neuron>();
  735. Neuron[] differenceNeuronsArray;
  736.  
  737. bool net1IsSmaller = false;
  738. Neuron[] net1Neurons = net1.GetNetworkArray();
  739. Neuron[] net2Neurons = net2.GetNetworkArray();
  740. Neuron[] tempNeurons = net1Neurons;
  741. ICollection keysCol;
  742. int[] keys;
  743.  
  744. if (net1Neurons.Length < net2Neurons.Length)
  745. {
  746. net1Neurons = net2Neurons;
  747. net2Neurons = tempNeurons;
  748. net1IsSmaller = true;
  749. }
  750.  
  751. for (int i = 0; i < net1Neurons.Length; i++)
  752. {
  753. Neuron neuron = new Neuron(net1Neurons[i].id,0f);
  754. Hashtable geneHash = new Hashtable();
  755. for (int j = 0; j < net1Neurons[i].incommingArray.Length; j++)
  756. {
  757. geneHash.Add(net1Neurons[i].incommingArray[j].inno, new Gene[] { net1Neurons[i].incommingArray[j], null});
  758. }
  759.  
  760. if (i <= net2Neurons.Length - 1)
  761. {
  762. for (int j = 0; j < net2Neurons[i].incommingArray.Length; j++)
  763. {
  764. if (geneHash.ContainsKey(net2Neurons[i].incommingArray[j].inno))
  765. {
  766. Gene[] genes = (Gene[])geneHash[net2Neurons[i].incommingArray[j].inno];
  767. genes[1] = net2Neurons[i].incommingArray[j];
  768. }
  769. else
  770. {
  771. geneHash.Add(net2Neurons[i].incommingArray[j].inno, new Gene[] { null, net2Neurons[i].incommingArray[j] });
  772. }
  773. }
  774. }
  775.  
  776. keysCol = geneHash.Keys; //get all keys from gene hash
  777. keys = new int[keysCol.Count]; //create array with size of number of keys
  778. keysCol.CopyTo(keys, 0); //copy all keys from ICollections to array
  779. keys = keys.OrderBy(x => x).ToArray(); //order keys in ascending order
  780.  
  781. for (int j = 0; j < keys.Length; j++)
  782. {
  783. Gene[] genes = (Gene[])geneHash[keys[j]];
  784. Gene gene = null;
  785. if (genes[0] != null)
  786. {
  787. gene = new Gene(genes[0]);
  788. if (genes[1] != null)
  789. {
  790. gene.weight = Mathf.Abs((gene.weight + genes[1].weight)/2f);
  791. }
  792. else
  793. {
  794. gene.weight = 100f;
  795. }
  796. }
  797. else
  798. {
  799. gene = new Gene(genes[1]);
  800. if (genes[0] != null)
  801. {
  802. gene.weight = Mathf.Abs((gene.weight + genes[0].weight) / 2f);
  803. }
  804. else
  805. {
  806. gene.weight = 100f;
  807. }
  808. }
  809.  
  810. //gene.weight = Mathf.Abs(gene.weight);
  811. neuron.incomming.Add(gene);
  812. }
  813.  
  814. differenceNeurons.Add(neuron);
  815. }
  816.  
  817. differenceNeurons.Sort((x, y) => x.id.CompareTo(y.id));
  818.  
  819. differenceNeuronsArray = differenceNeurons.ToArray();
  820. for (int i = 0; i < differenceNeuronsArray.Length; i++)
  821. {
  822. differenceNeuronsArray[i].incomming.Sort((x, y) => x.inNode.CompareTo(y.inNode));
  823. differenceNeuronsArray[i].incommingArray = differenceNeuronsArray[i].incomming.ToArray();
  824. }
  825.  
  826. difference = new NEATBrain(net1IsSmaller == true? net2:net1, differenceNeuronsArray);
  827.  
  828. return difference;
  829. }
  830.  
  831. public BehaviourGenome GetBehaviourGenome()
  832. {
  833. return behaviourGenome;
  834. }
  835.  
  836. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement