public NeuronNEAT(int nodeID, GeneNodeNEAT.GeneNodeType type, TransferFunctions.TransferFunction function) { id = nodeID; nodeType = type; currentValue = new float[1]; incomingConnectionsList = new List<ConnectionNEAT>(); activationFunction = function; }
public GenomeNEAT(int numInputs, int numHidden, int numOutputs) { // Constructor if (numInputs < 1 || numOutputs < 1) { Debug.LogError("New NEAT Genome requires at least 1 input and output node!! [" + numInputs.ToString() + "," + numOutputs.ToString() + "]"); } else { nodeNEATList = new List <GeneNodeNEAT>(); int currentID = 0; for (int i = 0; i < numInputs; i++) { GeneNodeNEAT newInputNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear); nodeNEATList.Add(newInputNode); currentID++; } for (int h = 0; h < numHidden; h++) { GeneNodeNEAT newHiddenNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.Hid, TransferFunctions.TransferFunction.RationalSigmoid); nodeNEATList.Add(newHiddenNode); currentID++; } for (int o = 0; o < numOutputs; o++) { GeneNodeNEAT newOutputNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid); nodeNEATList.Add(newOutputNode); currentID++; } linkNEATList = new List <GeneLinkNEAT>(); // Empty for now } }
public override object Read(ES2Reader reader) { GeneNodeNEAT data = new GeneNodeNEAT(); Read(reader, data); return(data); }
public GenomeNEAT(int numInputs, int numHidden, int numOutputs) { // Constructor if (numInputs < 1 || numOutputs < 1) { Debug.LogError("New NEAT Genome requires at least 1 input and output node!! [" + numInputs.ToString() + "," + numOutputs.ToString() + "]"); } else { nodeNEATList = new List<GeneNodeNEAT>(); int currentID = 0; for (int i = 0; i < numInputs; i++) { GeneNodeNEAT newInputNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear); nodeNEATList.Add(newInputNode); currentID++; } for (int h = 0; h < numHidden; h++) { GeneNodeNEAT newHiddenNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.Hid, TransferFunctions.TransferFunction.RationalSigmoid); nodeNEATList.Add(newHiddenNode); currentID++; } for (int o = 0; o < numOutputs; o++) { GeneNodeNEAT newOutputNode = new GeneNodeNEAT(currentID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid); nodeNEATList.Add(newOutputNode); currentID++; } linkNEATList = new List<GeneLinkNEAT>(); // Empty for now } }
public override void Write(object obj, ES2Writer writer) { GeneNodeNEAT data = (GeneNodeNEAT)obj; // Add your writer.Write calls here. writer.Write(0); // Version 0 is current version number // Make sure to edit Read() function to properly handle version control! // VERSION 0: writer.Write(data.activationFunction); writer.Write(data.id); writer.Write(data.nodeType); writer.Write(data.sourceAddonInno); writer.Write(data.sourceAddonRecursionNum); writer.Write(data.sourceAddonChannelNum); }
public override void Read(ES2Reader reader, object c) { GeneNodeNEAT data = (GeneNodeNEAT)c; // Add your reader.Read calls here to read the data into the object. // Read the version number. int fileVersion = reader.Read <int>(); // VERSION 0: if (fileVersion >= 0) { data.activationFunction = reader.Read <TransferFunctions.TransferFunction>(); data.id = reader.Read <int>(); data.nodeType = reader.Read <GeneNodeNEAT.GeneNodeType>(); data.sourceAddonInno = reader.Read <int>(); data.sourceAddonRecursionNum = reader.Read <int>(); data.sourceAddonChannelNum = reader.Read <int>(); } }
public void AddNewRandomNode(int gen, int inno) { if (linkNEATList.Count > 0) { int linkID = (int)UnityEngine.Random.Range(0f, (float)linkNEATList.Count); linkNEATList[linkID].enabled = false; // disable old connection GeneNodeNEAT newHiddenNode = new GeneNodeNEAT(nodeNEATList.Count, GeneNodeNEAT.GeneNodeType.Hid, TransferFunctions.TransferFunction.RationalSigmoid, inno, 0, false, 0); nodeNEATList.Add(newHiddenNode); // add new node between old connection // create two new connections GeneLinkNEAT newLinkA = new GeneLinkNEAT(linkNEATList[linkID].fromNodeID, GetInt3FromNodeIndex(newHiddenNode.id), linkNEATList[linkID].weight, true, GetNextInnovNumber(), gen); GeneLinkNEAT newLinkB = new GeneLinkNEAT(GetInt3FromNodeIndex(newHiddenNode.id), linkNEATList[linkID].toNodeID, 1f, true, GetNextInnovNumber(), gen); linkNEATList.Add(newLinkA); linkNEATList.Add(newLinkB); //Debug.Log("AddNewRandomNode() linkID: " + linkID.ToString() + ", "); } else { Debug.Log("No connections! Can't create new node!!!"); } }
public override object Read(ES2Reader reader) { GeneNodeNEAT data = new GeneNodeNEAT(); Read(reader, data); return data; }
public void AdjustBrainAfterBodyChange(ref CritterGenome bodyGenome) { // Try to do it assuming this function only took a CritterNode as input, rather than full bodyGenome: //CritterNode sourceNode = bodyGenome.CritterNodeList[bodyNodeID]; string beforeBrain = "AdjustBrain Before: \n"; string afterBrain = "AdjustBrain After: \n"; List <GeneNodeNEAT> newBrainNodeList = bodyGenome.GetBlankBrainNodesFromBody(); // doesn't include Hidden Nodes //List<GeneLinkNEAT> newBrainLinkList = new List<GeneLinkNEAT>(); // need to make a new copy so that the old link-list stays static while searching for matching from/toID's // Find number of Input+Output nodes in the old list: //int numOriginalInOutNodes = 0; //for (int i = 0; i < nodeNEATList.Count; i++) { // if(nodeNEATList[i].nodeType != GeneNodeNEAT.GeneNodeType.Hid) { // numOriginalInOutNodes++; // } //} // Compare this to the number of nodes in the new list (which doesn't contain any hidden nodes) //int netNewNodes = newBrainNodeList.Count - numOriginalInOutNodes; //Debug.Log("AdjustBrainAddedRecursion! numOriginalInOutNodes: " + numOriginalInOutNodes.ToString() + ", netNewNodes: " + netNewNodes.ToString() + ", bodyNodeID: " + bodyNodeID.ToString() + ", recursionNum: " + recursionNum.ToString()); int nextNodeIndexID = newBrainNodeList.Count; // where to start counting for hiddenNode ID's for (int i = 0; i < nodeNEATList.Count; i++) { beforeBrain += "Node " + nodeNEATList[i].id.ToString() + " (" + nodeNEATList[i].sourceAddonInno.ToString() + ", " + nodeNEATList[i].sourceAddonRecursionNum.ToString() + ", " + nodeNEATList[i].sourceAddonChannelNum.ToString() + ")\n"; if (nodeNEATList[i].nodeType == GeneNodeNEAT.GeneNodeType.Hid) { //Debug.Log("AdjustBrainAfterBodyChange HID NODE: nextNodeIndexID: " + (nextNodeIndexID).ToString()); GeneNodeNEAT clonedNode = new GeneNodeNEAT(nextNodeIndexID, nodeNEATList[i].nodeType, nodeNEATList[i].activationFunction, nodeNEATList[i].sourceAddonInno, nodeNEATList[i].sourceAddonRecursionNum, false, nodeNEATList[i].sourceAddonChannelNum); newBrainNodeList.Add(clonedNode); nextNodeIndexID++; } } for (int i = 0; i < newBrainNodeList.Count; i++) { afterBrain += "Node " + newBrainNodeList[i].id.ToString() + " (" + newBrainNodeList[i].sourceAddonInno.ToString() + ", " + newBrainNodeList[i].sourceAddonRecursionNum.ToString() + ", " + newBrainNodeList[i].sourceAddonChannelNum.ToString() + ")\n"; } // Once complete, replace oldNodeList with the new one: nodeNEATList = newBrainNodeList; //linkNEATList = newBrainLinkList; // Make sure that there aren't any links pointing to non-existent nodes: for (int i = 0; i < linkNEATList.Count; i++) { bool linkSevered = false; if (GetNodeIndexFromInt3(linkNEATList[i].fromNodeID) == -1) { linkSevered = true; } if (GetNodeIndexFromInt3(linkNEATList[i].toNodeID) == -1) { linkSevered = true; } if (linkSevered) { linkNEATList[i].enabled = false; //Debug.Log("LINK " + i.ToString() + " SEVERED!! " + linkNEATList[i].fromNodeID.ToString() + ", " + linkNEATList[i].toNodeID.ToString()); } } //Debug.Log(beforeBrain); //Debug.Log(afterBrain + "\n deltaNodes: " + netNewNodes.ToString()); }
public Population BreedPopulation(ref Population sourcePopulation, int currentGeneration) { #region Pre-Crossover, Figuring out how many agents to breed etc. int LifetimeGeneration = currentGeneration + sourcePopulation.trainingGenerations; int totalNumWeightMutations = 0; //float totalWeightChangeValue = 0f; // go through species list and adjust fitness List<SpeciesBreedingPool> childSpeciesPoolsList = new List<SpeciesBreedingPool>(); // will hold agents in an internal list to facilitate crossover for (int s = 0; s < sourcePopulation.speciesBreedingPoolList.Count; s++) { SpeciesBreedingPool newChildSpeciesPool = new SpeciesBreedingPool(sourcePopulation.speciesBreedingPoolList[s].templateGenome, sourcePopulation.speciesBreedingPoolList[s].speciesID); // create Breeding Pools // copies the existing breeding pools but leaves their agentLists empty for future children childSpeciesPoolsList.Add(newChildSpeciesPool); // Add to list of pools } sourcePopulation.RankAgentArray(); // based on modified species fitness score, so compensated for species sizes Agent[] newAgentArray = new Agent[sourcePopulation.masterAgentArray.Length]; // Calculate total fitness score: float totalScore = 0f; if (survivalByRaffle) { for (int a = 0; a < sourcePopulation.populationMaxSize; a++) { // iterate through all agents totalScore += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; } } // Figure out How many Agents survive int numSurvivors = Mathf.RoundToInt(survivalRate * (float)sourcePopulation.populationMaxSize); //Depending on method, one at a time, select an Agent to survive until the max Number is reached int newChildIndex = 0; // For ( num Agents ) { for (int i = 0; i < numSurvivors; i++) { // If survival is by fitness score ranking: if (survivalByRank) { // Pop should already be ranked, so just traverse from top (best) to bottom (worst) newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[newChildIndex]; SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; } // if survival is completely random, as a control: if (survivalStochastic) { int randomAgent = UnityEngine.Random.Range(0, numSurvivors - 1); // Set next newChild slot to a randomly-chosen agent within the survivor faction -- change to full random? newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[randomAgent]; SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; } // if survival is based on a fitness lottery: if (survivalByRaffle) { // Try when Fitness is normalized from 0-1 float randomSlicePosition = UnityEngine.Random.Range(0f, totalScore); float accumulatedFitness = 0f; for (int a = 0; a < sourcePopulation.populationMaxSize; a++) { // iterate through all agents accumulatedFitness += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; // if accum fitness is on slicePosition, copy this Agent //Debug.Log("NumSurvivors: " + numSurvivors.ToString() + ", Surviving Agent " + a.ToString() + ": AccumFitness: " + accumulatedFitness.ToString() + ", RafflePos: " + randomSlicePosition.ToString() + ", TotalScore: " + totalScore.ToString() + ", newChildIndex: " + newChildIndex.ToString()); if (accumulatedFitness >= randomSlicePosition) { newAgentArray[newChildIndex] = sourcePopulation.masterAgentArray[a]; // add to next gen's list of agents SpeciesBreedingPool survivingAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, newAgentArray[newChildIndex].speciesID); survivingAgentBreedingPool.AddNewAgent(newAgentArray[newChildIndex]); //SortNewAgentIntoSpecies(newAgentArray[newChildIndex], childSpeciesList); // sorts this surviving agent into next generation's species' newChildIndex++; break; } } } } // Figure out how many new agents must be created to fill up the new population: int numNewChildAgents = sourcePopulation.populationMaxSize - numSurvivors; int numEligibleBreederAgents = Mathf.RoundToInt(breedingRate * (float)sourcePopulation.populationMaxSize); int currentRankIndex = 0; // Once the agents are ranked, trim the BreedingPools of agents that didn't make the cut for mating: if(useSpeciation) { for (int s = 0; s < sourcePopulation.speciesBreedingPoolList.Count; s++) { int index = 0; int failsafe = 0; int numAgents = sourcePopulation.speciesBreedingPoolList[s].agentList.Count; while (index < numAgents) { if (index < sourcePopulation.speciesBreedingPoolList[s].agentList.Count) { if (sourcePopulation.speciesBreedingPoolList[s].agentList[index].fitnessRank >= numEligibleBreederAgents) { sourcePopulation.speciesBreedingPoolList[s].agentList.RemoveAt(index); } else { index++; } } else { break; } failsafe++; if (failsafe > 500) { Debug.Log("INFINITE LOOP! hit failsafe 500 iters -- Trimming BreedingPools!"); break; } } //Debug.Log("BreedPopulation -- TRIMSpeciesPool# " + s.ToString() + ", id: " + sourcePopulation.speciesBreedingPoolList[s].speciesID.ToString() + ", Count: " + sourcePopulation.speciesBreedingPoolList[s].agentList.Count.ToString()); // } } float totalScoreBreeders = 0f; if (breedingByRaffle) { // calculate total fitness scores to determine lottery weights for (int a = 0; a < numEligibleBreederAgents; a++) { // iterate through all agents totalScoreBreeders += sourcePopulation.masterAgentArray[a].fitnessScoreSpecies; } } #endregion // Iterate over numAgentsToCreate : int newChildrenCreated = 0; while (newChildrenCreated < numNewChildAgents) { // Find how many parents random number btw min/max: int numParentAgents = 2; // UnityEngine.Random.Range(minNumParents, maxNumParents); int numChildAgents = 1; // defaults to one child, but: if (numNewChildAgents - newChildrenCreated >= 2) { // room for two more! numChildAgents = 2; } Agent[] parentAgentsArray = new Agent[numParentAgents]; // assume 2 for now? yes, so far.... List<GeneNodeNEAT>[] parentNodeListArray = new List<GeneNodeNEAT>[numParentAgents]; List<GeneLinkNEAT>[] parentLinkListArray = new List<GeneLinkNEAT>[numParentAgents]; Agent firstParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); parentAgentsArray[0] = firstParentAgent; List<GeneNodeNEAT> firstParentNodeList = firstParentAgent.brainGenome.nodeNEATList; List<GeneLinkNEAT> firstParentLinkList = firstParentAgent.brainGenome.linkNEATList; //List<GeneNodeNEAT> firstParentNodeList = new List<GeneNodeNEAT>(); //List<GeneLinkNEAT> firstParentLinkList = new List<GeneLinkNEAT>(); //firstParentNodeList = firstParentAgent.brainGenome.nodeNEATList; //firstParentLinkList = firstParentAgent.brainGenome.linkNEATList; parentNodeListArray[0] = firstParentNodeList; parentLinkListArray[0] = firstParentLinkList; Agent secondParentAgent; SpeciesBreedingPool parentAgentBreedingPool = sourcePopulation.GetBreedingPoolByID(sourcePopulation.speciesBreedingPoolList, firstParentAgent.speciesID); if (useSpeciation) { //parentAgentBreedingPool float randBreedOutsideSpecies = UnityEngine.Random.Range(0f, 1f); if (randBreedOutsideSpecies < interspeciesBreedingRate) { // Attempts to Found a new species // allowed to breed outside its own species: secondParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); } else { // Selects mate only from within its own species: secondParentAgent = SelectAgentFromPoolForBreeding(parentAgentBreedingPool); } } else { secondParentAgent = SelectAgentFromPopForBreeding(sourcePopulation, numEligibleBreederAgents, ref currentRankIndex); } parentAgentsArray[1] = secondParentAgent; List<GeneNodeNEAT> secondParentNodeList = secondParentAgent.brainGenome.nodeNEATList; List<GeneLinkNEAT> secondParentLinkList = secondParentAgent.brainGenome.linkNEATList; //List<GeneNodeNEAT> secondParentNodeList = new List<GeneNodeNEAT>(); //List<GeneLinkNEAT> secondParentLinkList = new List<GeneLinkNEAT>(); //secondParentNodeList = secondParentAgent.brainGenome.nodeNEATList; //secondParentLinkList = secondParentAgent.brainGenome.linkNEATList; parentNodeListArray[1] = secondParentNodeList; parentLinkListArray[1] = secondParentLinkList; // Iterate over ChildArray.Length : // how many newAgents created for (int c = 0; c < numChildAgents; c++) { // for number of child Agents in floatArray[][]: Agent newChildAgent = new Agent(); List<GeneNodeNEAT> childNodeList = new List<GeneNodeNEAT>(); List<GeneLinkNEAT> childLinkList = new List<GeneLinkNEAT>(); GenomeNEAT childBrainGenome = new GenomeNEAT(); childBrainGenome.nodeNEATList = childNodeList; childBrainGenome.linkNEATList = childLinkList; int numEnabledLinkGenes = 0; if (useCrossover) { int nextLinkInnoA = 0; int nextLinkInnoB = 0; //int nextBodyNodeInno = 0; //int nextBodyAddonInno = 0; int failsafeMax = 500; int failsafe = 0; int parentListIndexA = 0; int parentListIndexB = 0; //int parentBodyNodeIndex = 0; bool parentDoneA = false; bool parentDoneB = false; bool endReached = false; int moreFitParent = 0; // which parent is more Fit if (parentAgentsArray[0].fitnessScoreSpecies < parentAgentsArray[1].fitnessScoreSpecies) { moreFitParent = 1; } else if (parentAgentsArray[0].fitnessScoreSpecies == parentAgentsArray[1].fitnessScoreSpecies) { moreFitParent = Mathf.RoundToInt(UnityEngine.Random.Range(0f, 1f)); } // MATCH UP Links between both agents, if they have a gene with matching Inno#, then mixing can occur while (!endReached) { failsafe++; if(failsafe > failsafeMax) { Debug.Log("failsafe reached!"); break; } // inno# of next links: if(parentLinkListArray[0].Count > parentListIndexA) { nextLinkInnoA = parentLinkListArray[0][parentListIndexA].innov; } else { parentDoneA = true; } if (parentLinkListArray[1].Count > parentListIndexB) { nextLinkInnoB = parentLinkListArray[1][parentListIndexB].innov; } else { parentDoneB = true; } int innoDelta = nextLinkInnoA - nextLinkInnoB; // 0=match, neg= Aextra, pos= Bextra if (parentDoneA && !parentDoneB) { innoDelta = 1; } if (parentDoneB && !parentDoneA) { innoDelta = -1; } if (parentDoneA && parentDoneB) { // reached end of both parent's linkLists endReached = true; break; } if (innoDelta < 0) { // Parent A has an earlier link mutation //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta < 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString()); if (moreFitParent == 0) { // Parent A is more fit: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, parentLinkListArray[0][parentListIndexA].weight, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[0][parentListIndexA].enabled) numEnabledLinkGenes++; } else { if(CheckForMutation(crossoverRandomLinkChance)) { // was less fit parent, but still passed on a gene!: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, parentLinkListArray[0][parentListIndexA].weight, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); } } parentListIndexA++; } if (innoDelta > 0) { // Parent B has an earlier link mutation //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta > 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString()); if (moreFitParent == 1) { // Parent B is more fit: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[1][parentListIndexB].fromNodeID, parentLinkListArray[1][parentListIndexB].toNodeID, parentLinkListArray[1][parentListIndexB].weight, parentLinkListArray[1][parentListIndexB].enabled, parentLinkListArray[1][parentListIndexB].innov, parentLinkListArray[1][parentListIndexB].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[1][parentListIndexB].enabled) numEnabledLinkGenes++; } else { if (CheckForMutation(crossoverRandomLinkChance)) { // was less fit parent, but still passed on a gene!: GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[1][parentListIndexB].fromNodeID, parentLinkListArray[1][parentListIndexB].toNodeID, parentLinkListArray[1][parentListIndexB].weight, parentLinkListArray[1][parentListIndexB].enabled, parentLinkListArray[1][parentListIndexB].innov, parentLinkListArray[1][parentListIndexB].birthGen); childLinkList.Add(newChildLink); } } parentListIndexB++; } if (innoDelta == 0) { // Match! float randParentIndex = UnityEngine.Random.Range(0f, 1f); float newWeightValue; if (randParentIndex < 0.5) { // ParentA wins: newWeightValue = parentLinkListArray[0][parentListIndexA].weight; } else { // ParentB wins: newWeightValue = parentLinkListArray[1][parentListIndexB].weight; } //Debug.Log("newChildIndex: " + newChildIndex.ToString() + ", IndexA: " + parentListIndexA.ToString() + ", IndexB: " + parentListIndexB.ToString() + ", innoDelta == 0 (" + innoDelta.ToString() + ") -- moreFitP: " + moreFitParent.ToString() + ", nextLinkInnoA: " + nextLinkInnoA.ToString() + ", nextLinkInnoB: " + nextLinkInnoB.ToString() + ", randParent: " + randParentIndex.ToString() + ", weight: " + newWeightValue.ToString()); GeneLinkNEAT newChildLink = new GeneLinkNEAT(parentLinkListArray[0][parentListIndexA].fromNodeID, parentLinkListArray[0][parentListIndexA].toNodeID, newWeightValue, parentLinkListArray[0][parentListIndexA].enabled, parentLinkListArray[0][parentListIndexA].innov, parentLinkListArray[0][parentListIndexA].birthGen); childLinkList.Add(newChildLink); if (parentLinkListArray[0][parentListIndexA].enabled) numEnabledLinkGenes++; parentListIndexA++; parentListIndexB++; } } // once childLinkList is built -- use nodes of the moreFit parent: for (int i = 0; i < parentNodeListArray[moreFitParent].Count; i++) { // iterate through all nodes in the parent List and copy them into fresh new geneNodes: GeneNodeNEAT clonedNode = new GeneNodeNEAT(parentNodeListArray[moreFitParent][i].id, parentNodeListArray[moreFitParent][i].nodeType, parentNodeListArray[moreFitParent][i].activationFunction, parentNodeListArray[moreFitParent][i].sourceAddonInno, parentNodeListArray[moreFitParent][i].sourceAddonRecursionNum, false, parentNodeListArray[moreFitParent][i].sourceAddonChannelNum); childNodeList.Add(clonedNode); } if (useMutation) { // BODY MUTATION: //PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); // NEED TO ADJUST BRAINS IF MUTATION CHANGES #NODES!!!! // BRAIN MUTATION: if (numEnabledLinkGenes < 1) numEnabledLinkGenes = 1; for (int k = 0; k < childLinkList.Count; k++) { float mutateChance = mutationBlastModifier * masterMutationRate / (1f + (float)numEnabledLinkGenes * 0.15f); if (LifetimeGeneration - childLinkList[k].birthGen < newLinkBonusDuration) { float t = 1 - ((LifetimeGeneration - childLinkList[k].birthGen) / (float)newLinkBonusDuration); // t=0 means age of gene is same as bonusDuration, t=1 means it is brand new mutateChance = Mathf.Lerp(mutateChance, mutateChance * newLinkMutateBonus, t); } if (CheckForMutation(mutateChance)) { // Weight Mutation! //Debug.Log("Weight Mutation Link[" + k.ToString() + "] weight: " + childLinkList[k].weight.ToString() + ", mutate: " + MutateFloat(childLinkList[k].weight).ToString()); childLinkList[k].weight = MutateFloat(childLinkList[k].weight); totalNumWeightMutations++; } } if (CheckForMutation(mutationBlastModifier * mutationRemoveLinkChance)) { //Debug.Log("Remove Link Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomLink(); } if (CheckForMutation(mutationBlastModifier * mutationAddNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.AddNewRandomNode(LifetimeGeneration, GetNextAddonInnov()); } if (CheckForMutation(mutationBlastModifier * mutationRemoveNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomNode(); } if (CheckForMutation(mutationBlastModifier * mutationAddLinkChance)) { // Adds new connection //Debug.Log("Add Link Mutation Agent[" + newChildIndex.ToString() + "]"); if (CheckForMutation(existingNetworkBias)) { childBrainGenome.AddNewExtraLink(existingFromNodeBias, LifetimeGeneration); } else { childBrainGenome.AddNewRandomLink(LifetimeGeneration); } } if (CheckForMutation(mutationBlastModifier * mutationActivationFunctionChance)) { TransferFunctions.TransferFunction newFunction; int randIndex = Mathf.RoundToInt(UnityEngine.Random.Range(0f, childNodeList.Count - 1)); int randomTF = (int)UnityEngine.Random.Range(0f, 12f); switch (randomTF) { case 0: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 1: newFunction = TransferFunctions.TransferFunction.Linear; break; case 2: newFunction = TransferFunctions.TransferFunction.Gaussian; break; case 3: newFunction = TransferFunctions.TransferFunction.Abs; break; case 4: newFunction = TransferFunctions.TransferFunction.Cos; break; case 5: newFunction = TransferFunctions.TransferFunction.Sin; break; case 6: newFunction = TransferFunctions.TransferFunction.Tan; break; case 7: newFunction = TransferFunctions.TransferFunction.Square; break; case 8: newFunction = TransferFunctions.TransferFunction.Threshold01; break; case 9: newFunction = TransferFunctions.TransferFunction.ThresholdNegPos; break; case 10: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 11: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 12: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; default: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; } if (childNodeList[randIndex].nodeType != GeneNodeNEAT.GeneNodeType.Out) { // keep outputs -1 to 1 range Debug.Log("ActivationFunction Mutation Node[" + randIndex.ToString() + "] prev: " + childNodeList[randIndex].activationFunction.ToString() + ", new: " + newFunction.ToString()); childNodeList[randIndex].activationFunction = newFunction; } } } else { Debug.Log("Mutation Disabled!"); } // THE BODY ==========!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!====================================================================================== CritterGenome childBodyGenome = new CritterGenome(); // create new body genome for Child // This creates the ROOT NODE!!!! // Clone Nodes & Addons from more fit parent to create new child body genome // crossover is on, so check for matching Nodes and Add-ons (based on Inno#'s) to determine when to mix Settings/Attributes: // Iterate over the nodes of the more fit parent: for (int i = 0; i < parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList.Count; i++) { int currentNodeInno = parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[i].innov; if (i == 0) { // if this is the ROOT NODE: childBodyGenome.CritterNodeList[0].CopySettingsFromNode(parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[0]); // The root node was already created during the Constructor method of the CritterGenome, // ... so instead of creating a new one, just copy the settings } else { // NOT the root node, proceed normally: // Create new cloned node defaulted to the settings of the source( more-fit parent's) Node: CritterNode clonedCritterNode = parentAgentsArray[moreFitParent].bodyGenome.CritterNodeList[i].CloneThisCritterNode(); // Check other parent for same node: for (int j = 0; j < parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList.Count; j++) { if (parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList[j].innov == currentNodeInno) { // CROSSOVER NODE SETTINGS HERE!!! ---- If random dice roll > 0.5, use less fit parent's settings, otherwise leave as default BodyCrossover(ref clonedCritterNode, parentAgentsArray[1 - moreFitParent].bodyGenome.CritterNodeList[j]); } } childBodyGenome.CritterNodeList.Add(clonedCritterNode); } } // ADD-ONS!!!!!!!!!!!!!!!!!!!!!! BreedCritterAddons(ref childBodyGenome, ref parentAgentsArray[moreFitParent].bodyGenome, ref parentAgentsArray[1 - moreFitParent].bodyGenome); newChildAgent.bodyGenome = childBodyGenome; // ????? if (useMutation) { // BODY MUTATION: PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); } } else { // no crossover: //=============================================================================================== for (int i = 0; i < parentNodeListArray[0].Count; i++) { // iterate through all nodes in the parent List and copy them into fresh new geneNodes: GeneNodeNEAT clonedNode = new GeneNodeNEAT(parentNodeListArray[0][i].id, parentNodeListArray[0][i].nodeType, parentNodeListArray[0][i].activationFunction, parentNodeListArray[0][i].sourceAddonInno, parentNodeListArray[0][i].sourceAddonRecursionNum, false, parentNodeListArray[0][i].sourceAddonChannelNum); childNodeList.Add(clonedNode); } for (int j = 0; j < parentLinkListArray[0].Count; j++) { //same thing with connections GeneLinkNEAT clonedLink = new GeneLinkNEAT(parentLinkListArray[0][j].fromNodeID, parentLinkListArray[0][j].toNodeID, parentLinkListArray[0][j].weight, parentLinkListArray[0][j].enabled, parentLinkListArray[0][j].innov, parentLinkListArray[0][j].birthGen); childLinkList.Add(clonedLink); if (parentLinkListArray[0][j].enabled) numEnabledLinkGenes++; } // MUTATION: if (useMutation) { // BODY MUTATION: //childBrainGenome.nodeNEATList = childNodeList //PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); // BRAIN MUTATION: if (numEnabledLinkGenes < 1) numEnabledLinkGenes = 1; for (int k = 0; k < childLinkList.Count; k++) { float mutateChance = mutationBlastModifier * masterMutationRate / (1f + (float)numEnabledLinkGenes * 0.15f); if (LifetimeGeneration - childLinkList[k].birthGen < newLinkBonusDuration) { float t = 1 - ((LifetimeGeneration - childLinkList[k].birthGen) / (float)newLinkBonusDuration); // t=0 means age of gene is same as bonusDuration, t=1 means it is brand new mutateChance = Mathf.Lerp(mutateChance, mutateChance * newLinkMutateBonus, t); } if (CheckForMutation(mutateChance)) { // Weight Mutation! //Debug.Log("Weight Mutation Link[" + k.ToString() + "] weight: " + childLinkList[k].weight.ToString() + ", mutate: " + MutateFloat(childLinkList[k].weight).ToString()); childLinkList[k].weight = MutateFloat(childLinkList[k].weight); totalNumWeightMutations++; } } if (CheckForMutation(mutationBlastModifier * mutationRemoveLinkChance)) { //Debug.Log("Remove Link Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.RemoveRandomLink(); } if (CheckForMutation(mutationBlastModifier * mutationAddNodeChance)) { // Adds a new node //Debug.Log("Add Node Mutation Agent[" + newChildIndex.ToString() + "]"); childBrainGenome.AddNewRandomNode(LifetimeGeneration, GetNextAddonInnov()); } if (CheckForMutation(mutationBlastModifier * mutationAddLinkChance)) { // Adds new connection //Debug.Log("Add Link Mutation Agent[" + newChildIndex.ToString() + "]"); if(CheckForMutation(existingNetworkBias)) { childBrainGenome.AddNewExtraLink(existingFromNodeBias, LifetimeGeneration); } else { childBrainGenome.AddNewRandomLink(LifetimeGeneration); } } if (CheckForMutation(mutationBlastModifier * mutationActivationFunctionChance)) { TransferFunctions.TransferFunction newFunction; int randIndex = Mathf.RoundToInt(UnityEngine.Random.Range(0f, childNodeList.Count - 1)); int randomTF = (int)UnityEngine.Random.Range(0f, 12f); switch (randomTF) { case 0: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 1: newFunction = TransferFunctions.TransferFunction.Linear; break; case 2: newFunction = TransferFunctions.TransferFunction.Gaussian; break; case 3: newFunction = TransferFunctions.TransferFunction.Abs; break; case 4: newFunction = TransferFunctions.TransferFunction.Cos; break; case 5: newFunction = TransferFunctions.TransferFunction.Sin; break; case 6: newFunction = TransferFunctions.TransferFunction.Tan; break; case 7: newFunction = TransferFunctions.TransferFunction.Square; break; case 8: newFunction = TransferFunctions.TransferFunction.Threshold01; break; case 9: newFunction = TransferFunctions.TransferFunction.ThresholdNegPos; break; case 10: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 11: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; case 12: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; default: newFunction = TransferFunctions.TransferFunction.RationalSigmoid; break; } if (childNodeList[randIndex].nodeType != GeneNodeNEAT.GeneNodeType.Out) { // keep outputs -1 to 1 range Debug.Log("ActivationFunction Mutation Node[" + randIndex.ToString() + "] prev: " + childNodeList[randIndex].activationFunction.ToString() + ", new: " + newFunction.ToString()); childNodeList[randIndex].activationFunction = newFunction; } } //for (int t = 0; t < childNodeList.Count; t++) { //} } else { Debug.Log("Mutation Disabled!"); } // THE BODY!!!!! ++++++++++++++++++++++================+++++++++++++++++++===============+++++++++++++++++++===================+++++++++++++++++============== CritterGenome childBodyGenome = new CritterGenome(); // create new body genome for Child // Iterate over the nodes of the more fit parent: for (int i = 0; i < parentAgentsArray[0].bodyGenome.CritterNodeList.Count; i++) { int currentNodeInno = parentAgentsArray[0].bodyGenome.CritterNodeList[i].innov; if (i == 0) { // if this is the ROOT NODE: childBodyGenome.CritterNodeList[0].CopySettingsFromNode(parentAgentsArray[0].bodyGenome.CritterNodeList[0]); // The root node was already created during the Constructor method of the CritterGenome, // ... so instead of creating a new one, just copy the settings } else { // NOT the root node, proceed normally: // Create new cloned node defaulted to the settings of the source( more-fit parent's) Node: CritterNode clonedCritterNode = parentAgentsArray[0].bodyGenome.CritterNodeList[i].CloneThisCritterNode(); childBodyGenome.CritterNodeList.Add(clonedCritterNode); } } // ADD-ONS!!!!!!!!!!!!!!!!!!!!!! BreedCritterAddons(ref childBodyGenome, ref parentAgentsArray[0].bodyGenome, ref parentAgentsArray[0].bodyGenome); newChildAgent.bodyGenome = childBodyGenome; if (useMutation) { // BODY MUTATION: PerformBodyMutation(ref childBodyGenome, ref childBrainGenome); } } newChildAgent.brainGenome = childBrainGenome; //newChildAgent.brainGenome.nodeNEATList = childNodeList; //newChildAgent.brainGenome.linkNEATList = childLinkList; BrainNEAT childBrain = new BrainNEAT(newChildAgent.brainGenome); childBrain.BuildBrainNetwork(); newChildAgent.brain = childBrain; //Debug.Log("NEW CHILD numNodes: " + newChildAgent.brainGenome.nodeNEATList.Count.ToString() + ", #Neurons: " + newChildAgent.brain.neuronList.Count.ToString()); //newChildAgent.bodyGenome.PreBuildCritter(0.8f); // Species: if (useSpeciation) { float randAdoption = UnityEngine.Random.Range(0f, 1f); if (randAdoption < adoptionRate) { // Attempts to Found a new species bool speciesGenomeMatch = false; for (int s = 0; s < childSpeciesPoolsList.Count; s++) { float geneticDistance = GenomeNEAT.MeasureGeneticDistance(newChildAgent.brainGenome, childSpeciesPoolsList[s].templateGenome, neuronWeight, linkWeight, weightWeight, normalizeExcess, normalizeDisjoint, normalizeLinkWeight); if (geneticDistance < speciesSimilarityThreshold) { speciesGenomeMatch = true; //agent.speciesID = speciesBreedingPoolList[s].speciesID; // this is done inside the AddNewAgent method below v v v childSpeciesPoolsList[s].AddNewAgent(newChildAgent); //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") SortAgentIntoBreedingPool dist: " + geneticDistance.ToString() + ", speciesIDs: " + newChildAgent.speciesID.ToString() + ", " + childSpeciesPoolsList[s].speciesID.ToString() + ", speciesCount: " + childSpeciesPoolsList[s].agentList.Count.ToString()); break; } } if (!speciesGenomeMatch) { SpeciesBreedingPool newSpeciesBreedingPool = new SpeciesBreedingPool(newChildAgent.brainGenome, sourcePopulation.GetNextSpeciesID()); // creates new speciesPool modeled on this agent's genome newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool childSpeciesPoolsList.Add(newSpeciesBreedingPool); // add new speciesPool to the population's list of all active species //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") SortAgentIntoBreedingPool NO MATCH!!! -- creating new BreedingPool " + newSpeciesBreedingPool.speciesID.ToString() + ", newChildAgentSpeciesID: " + newChildAgent.speciesID.ToString()); } } else { // joins parent species automatically: SpeciesBreedingPool newSpeciesBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, parentAgentBreedingPool.speciesID); newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool //Debug.Log(" NEW CHILD (" + newChildIndex.ToString() + ") NO ADOPTION SortAgentIntoBreedingPool speciesIDs: " + newChildAgent.speciesID.ToString() + ", " + newSpeciesBreedingPool.speciesID.ToString() + ", speciesCount: " + newSpeciesBreedingPool.agentList.Count.ToString()); } } else { // joins parent species automatically: SpeciesBreedingPool newSpeciesBreedingPool = sourcePopulation.GetBreedingPoolByID(childSpeciesPoolsList, parentAgentBreedingPool.speciesID); newSpeciesBreedingPool.AddNewAgent(newChildAgent); // add this agent to breeding pool } newChildAgent.parentFitnessScoreA = sourcePopulation.masterAgentArray[newChildIndex].fitnessScore; newAgentArray[newChildIndex] = newChildAgent; newChildIndex++; // new child created! newChildrenCreated++; } } /*Debug.Log("Finished Crossover! childSpeciesPoolsList:"); for (int i = 0; i < sourcePopulation.speciesBreedingPoolList.Count; i++) { string poolString = " Child Species ID: " + sourcePopulation.speciesBreedingPoolList[i].speciesID.ToString(); for (int j = 0; j < sourcePopulation.speciesBreedingPoolList[i].agentList.Count; j++) { poolString += ", member# " + j.ToString() + ", species: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].speciesID.ToString() + ", fitRank: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].fitnessRank.ToString(); } Debug.Log(poolString); }*/ // Clear out extinct species: int listIndex = 0; for (int s = 0; s < childSpeciesPoolsList.Count; s++) { if (listIndex >= childSpeciesPoolsList.Count) { Debug.Log("end childSpeciesPoolsList " + childSpeciesPoolsList.Count.ToString() + ", index= " + listIndex.ToString()); break; } else { if (childSpeciesPoolsList[listIndex].agentList.Count == 0) { // if empty: //Debug.Log("Species " + childSpeciesPoolsList[listIndex].speciesID.ToString() + " WENT EXTINCT!!! --- childSpeciesPoolsList[" + listIndex.ToString() + "] old Count: " + childSpeciesPoolsList.Count.ToString() + ", s: " + s.ToString()); childSpeciesPoolsList.RemoveAt(listIndex); //s--; // see if this works } else { listIndex++; } } } Debug.Log("Finished Crossover! totalNumWeightMutations: " + totalNumWeightMutations.ToString() + ", mutationBlastModifier: " + mutationBlastModifier.ToString() + ", bodyMutationBlastModifier: " + bodyMutationBlastModifier.ToString() + ", LifetimeGeneration: " + LifetimeGeneration.ToString() + ", currentGeneration: " + currentGeneration.ToString() + ", sourcePopulation.trainingGenerations: " + sourcePopulation.trainingGenerations.ToString()); sourcePopulation.masterAgentArray = newAgentArray; sourcePopulation.speciesBreedingPoolList = childSpeciesPoolsList; /*Debug.Log("Finished Crossover! sourcePopulation.speciesBreedingPoolList:"); for (int i = 0; i < sourcePopulation.speciesBreedingPoolList.Count; i++) { string poolString = "New Species ID: " + sourcePopulation.speciesBreedingPoolList[i].speciesID.ToString(); for (int j = 0; j < sourcePopulation.speciesBreedingPoolList[i].agentList.Count; j++) { poolString += ", member# " + j.ToString() + ", species: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].speciesID.ToString() + ", fitRank: " + sourcePopulation.speciesBreedingPoolList[i].agentList[j].fitnessRank.ToString(); } Debug.Log(poolString); }*/ return sourcePopulation; }
public List<GeneNodeNEAT> GetBlankBrainNodesFromBody() { List<GeneNodeNEAT> newNodeList = new List<GeneNodeNEAT>(); // Split into Input/Output list and put together afterward? List<GeneNodeNEAT> inputNodeList = new List<GeneNodeNEAT>(); List<GeneNodeNEAT> outputNodeList = new List<GeneNodeNEAT>(); int numSegments = 0; int numInputs = 0; int numOutputs = 0; bool isPendingChildren = true; int currentDepth = 0; // start with RootNode int maxDepth = 20; // safeguard to prevent while loop lock int nextSegmentID = 0; int currentBrainNodeID = 0; List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>(); // keeps track of all current-depth segment build-requests, and holds important metadata List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>(); // used to keep track of next childSegments that need to be built // *********** Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on. BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo(); rootSegmentBuildInfo.sourceNode = CritterNodeList[0]; currentBuildSegmentList.Add(rootSegmentBuildInfo); // ROOT NODE IS SPECIAL! // Do a Breadth-first traversal?? while (isPendingChildren) { for (int i = 0; i < currentBuildSegmentList.Count; i++) { numSegments++; nextSegmentID++; // PhysicalAttributes no inputs/outputs #region INPUTS // Joint Angle Sensors: if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointAngleSensor> jointAngleSensorList = CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointAngleSensorList.Count; j++) { // HINGE X X X X X if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { if (jointAngleSensorList[j].measureVel[0]) { // ALSO MEASURES ANGULAR VELOCITY: numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { // Only Angle, no velocity: numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { if (jointAngleSensorList[j].measureVel[0]) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT4 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 3); inputNodeList.Add(newNodeNEAT4); currentBrainNodeID++; } else { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } } } } List<AddonContactSensor> contactSensorList = CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID); for(int j = 0; j < contactSensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, contactSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonRaycastSensor> raycastSensorList = CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < raycastSensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, raycastSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonCompassSensor1D> compassSensor1DList = CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonCompassSensor3D> compassSensor3DList = CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < compassSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonPositionSensor1D> positionSensor1DList = CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonPositionSensor3D> positionSensor3DList = CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < positionSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonRotationSensor1D> rotationSensor1DList = CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonRotationSensor3D> rotationSensor3DList = CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < rotationSensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonVelocitySensor1D> velocitySensor1DList = CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor1DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonVelocitySensor3D> velocitySensor3DList = CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < velocitySensor3DList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); inputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numInputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); inputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonAltimeter> altimeterList = CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < altimeterList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, altimeterList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonEarBasic> earBasicList = CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < earBasicList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, earBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonGravitySensor> gravitySensorList = CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < gravitySensorList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, gravitySensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonOscillatorInput> oscillatorInputList = CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < oscillatorInputList.Count; j++) { numInputs++; //Debug.Log("Oscillator: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString()); GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonValueInput> valueInputList = CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < valueInputList.Count; j++) { numInputs++; //Debug.Log("Value: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString()); GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } //Debug.Log(currentBuildSegmentList[i].sourceNode.ID.ToString() + " oscillatorInputList Count: " + oscillatorInputList.Count.ToString() + ", valueInputList Count: " + valueInputList.Count.ToString()); List<AddonTimerInput> timerInputList = CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < timerInputList.Count; j++) { numInputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, timerInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); inputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } #endregion #region OUTPUTS: if (currentBuildSegmentList[i].sourceNode.ID != 0) { // is NOT ROOT segment -- Look into doing Root build BEFORE for loop to avoid the need to do this check List<AddonJointMotor> jointMotorList = CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < jointMotorList.Count; j++) { if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; } } // %%%%%% DO I STILL NEED THIS SECTION??? // Check for if the segment currently being built is a Mirror COPY: /*if (currentBuildSegmentList[i].isMirror) { //Debug.Log("This is a MIRROR COPY segment - Wow!"); if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) { // Invert the X-axis (this will propagate down to all this segment's children //newSegment.mirrorX = !newSegment.mirrorX; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) { //newSegment.mirrorY = !newSegment.mirrorY; } else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) { //newSegment.mirrorZ = !newSegment.mirrorZ; } }*/ } List<AddonThrusterEffector1D> thrusterEffector1DList = CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector1DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonThrusterEffector3D> thrusterEffector3DList = CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < thrusterEffector3DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); outputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonTorqueEffector1D> torqueEffector1DList = CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector1DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonTorqueEffector3D> torqueEffector3DList = CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < torqueEffector3DList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT1); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1); outputNodeList.Add(newNodeNEAT2); currentBrainNodeID++; numOutputs++; GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2); outputNodeList.Add(newNodeNEAT3); currentBrainNodeID++; } List<AddonMouthBasic> mouthBasicList = CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < mouthBasicList.Count; j++) { // BLANK FOR NOW!!! } List<AddonNoiseMakerBasic> noiseMakerBasicList = CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < noiseMakerBasicList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, noiseMakerBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonSticky> stickyList = CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < stickyList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, stickyList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } List<AddonWeaponBasic> weaponBasicList = CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID); for (int j = 0; j < weaponBasicList.Count; j++) { numOutputs++; GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, weaponBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0); outputNodeList.Add(newNodeNEAT); currentBrainNodeID++; } #endregion // CHECK FOR RECURSION: if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions: if (currentBuildSegmentList[i].recursionNumber < currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // if the current buildOrder's recursion number is less than the numRecursions there should be: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode; // request a segment to be built again based on the current sourceNode newSegmentInfo.recursionNumber = currentBuildSegmentList[i].recursionNumber + 1; // increment num recursions newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; nextBuildSegmentList.Add(newSegmentInfo); //Debug.Log("newSegmentInfo recursion# " + newSegmentInfo.recursionNumber.ToString() + ", currentBuildList[i].recNum: " + currentBuildSegmentList[i].recursionNumber.ToString()); // If the node also has Symmetry: if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode; // uses same sourceNode, but tags as Mirror: newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original newSegmentInfoMirror.recursionNumber = newSegmentInfo.recursionNumber; // !!!!!!!!!!!!! HIGHLY SUSPECT!!!! nextBuildSegmentList.Add(newSegmentInfoMirror); } } else { // at the end of a recursion chain, so do not add any other pendingChild builds } } // Figure out how many unique Child nodes this built node has: int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count; //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString()); for (int c = 0; c < numberOfChildNodes; c++) { // if NO symmetry: // Check if Attaching to a recursion chain && if onlyattachToTail is active: int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c]; if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) { if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { if (currentBuildSegmentList[i].recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) { // Only build segment if it is on the end of a recursion chain: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!! BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } else { // proceed normally: BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo(); newSegmentInfo.sourceNode = CritterNodeList[childID]; newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror; //newSegmentInfo.parentSegment = newSegment; nextBuildSegmentList.Add(newSegmentInfo); if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) { // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment: BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo(); newSegmentInfoMirror.sourceNode = CritterNodeList[childID]; newSegmentInfoMirror.isMirror = true; // This segment is the COPY, not the original //newSegmentInfoMirror.parentSegment = newSegment; // nextBuildSegmentList.Add(newSegmentInfoMirror); } } } } // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue currentBuildSegmentList.Clear(); // SWAP LISTS: if (nextBuildSegmentList.Count > 0) { for (int j = 0; j < nextBuildSegmentList.Count; j++) { currentBuildSegmentList.Add(nextBuildSegmentList[j]); } nextBuildSegmentList.Clear(); // empty this list for next depth-round } else { isPendingChildren = false; } if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up isPendingChildren = false; } currentDepth++; } for(int i = 0; i < inputNodeList.Count; i++) { newNodeList.Add(inputNodeList[i]); } for (int i = 0; i < outputNodeList.Count; i++) { newNodeList.Add(outputNodeList[i]); } for (int i = 0; i < newNodeList.Count; i++) { newNodeList[i].id = i; // Re-number nodes so that their list Index is always the same as their ID } return newNodeList; }
public void AddNewRandomNode(int gen, int inno) { if(linkNEATList.Count > 0) { int linkID = (int)UnityEngine.Random.Range(0f, (float)linkNEATList.Count); linkNEATList[linkID].enabled = false; // disable old connection GeneNodeNEAT newHiddenNode = new GeneNodeNEAT(nodeNEATList.Count, GeneNodeNEAT.GeneNodeType.Hid, TransferFunctions.TransferFunction.RationalSigmoid, inno, 0, false, 0); nodeNEATList.Add(newHiddenNode); // add new node between old connection // create two new connections GeneLinkNEAT newLinkA = new GeneLinkNEAT(linkNEATList[linkID].fromNodeID, GetInt3FromNodeIndex(newHiddenNode.id), linkNEATList[linkID].weight, true, GetNextInnovNumber(), gen); GeneLinkNEAT newLinkB = new GeneLinkNEAT(GetInt3FromNodeIndex(newHiddenNode.id), linkNEATList[linkID].toNodeID, 1f, true, GetNextInnovNumber(), gen); linkNEATList.Add(newLinkA); linkNEATList.Add(newLinkB); //Debug.Log("AddNewRandomNode() linkID: " + linkID.ToString() + ", "); } else { Debug.Log("No connections! Can't create new node!!!"); } }
public void AdjustBrainAfterBodyChange(ref CritterGenome bodyGenome) { // Try to do it assuming this function only took a CritterNode as input, rather than full bodyGenome: //CritterNode sourceNode = bodyGenome.CritterNodeList[bodyNodeID]; string beforeBrain = "AdjustBrain Before: \n"; string afterBrain = "AdjustBrain After: \n"; List<GeneNodeNEAT> newBrainNodeList = bodyGenome.GetBlankBrainNodesFromBody(); // doesn't include Hidden Nodes //List<GeneLinkNEAT> newBrainLinkList = new List<GeneLinkNEAT>(); // need to make a new copy so that the old link-list stays static while searching for matching from/toID's // Find number of Input+Output nodes in the old list: //int numOriginalInOutNodes = 0; //for (int i = 0; i < nodeNEATList.Count; i++) { // if(nodeNEATList[i].nodeType != GeneNodeNEAT.GeneNodeType.Hid) { // numOriginalInOutNodes++; // } //} // Compare this to the number of nodes in the new list (which doesn't contain any hidden nodes) //int netNewNodes = newBrainNodeList.Count - numOriginalInOutNodes; //Debug.Log("AdjustBrainAddedRecursion! numOriginalInOutNodes: " + numOriginalInOutNodes.ToString() + ", netNewNodes: " + netNewNodes.ToString() + ", bodyNodeID: " + bodyNodeID.ToString() + ", recursionNum: " + recursionNum.ToString()); int nextNodeIndexID = newBrainNodeList.Count; // where to start counting for hiddenNode ID's for (int i = 0; i < nodeNEATList.Count; i++) { beforeBrain += "Node " + nodeNEATList[i].id.ToString() + " (" + nodeNEATList[i].sourceAddonInno.ToString() + ", " + nodeNEATList[i].sourceAddonRecursionNum.ToString() + ", " + nodeNEATList[i].sourceAddonChannelNum.ToString() + ")\n"; if (nodeNEATList[i].nodeType == GeneNodeNEAT.GeneNodeType.Hid) { //Debug.Log("AdjustBrainAfterBodyChange HID NODE: nextNodeIndexID: " + (nextNodeIndexID).ToString()); GeneNodeNEAT clonedNode = new GeneNodeNEAT(nextNodeIndexID, nodeNEATList[i].nodeType, nodeNEATList[i].activationFunction, nodeNEATList[i].sourceAddonInno, nodeNEATList[i].sourceAddonRecursionNum, false, nodeNEATList[i].sourceAddonChannelNum); newBrainNodeList.Add(clonedNode); nextNodeIndexID++; } } for (int i = 0; i < newBrainNodeList.Count; i++) { afterBrain += "Node " + newBrainNodeList[i].id.ToString() + " (" + newBrainNodeList[i].sourceAddonInno.ToString() + ", " + newBrainNodeList[i].sourceAddonRecursionNum.ToString() + ", " + newBrainNodeList[i].sourceAddonChannelNum.ToString() + ")\n"; } // Once complete, replace oldNodeList with the new one: nodeNEATList = newBrainNodeList; //linkNEATList = newBrainLinkList; // Make sure that there aren't any links pointing to non-existent nodes: for (int i = 0; i < linkNEATList.Count; i++) { bool linkSevered = false; if (GetNodeIndexFromInt3(linkNEATList[i].fromNodeID) == -1) { linkSevered = true; } if (GetNodeIndexFromInt3(linkNEATList[i].toNodeID) == -1) { linkSevered = true; } if (linkSevered) { linkNEATList[i].enabled = false; //Debug.Log("LINK " + i.ToString() + " SEVERED!! " + linkNEATList[i].fromNodeID.ToString() + ", " + linkNEATList[i].toNodeID.ToString()); } } //Debug.Log(beforeBrain); //Debug.Log(afterBrain + "\n deltaNodes: " + netNewNodes.ToString()); }